中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档 | 网通镜像
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > Java > 综合文章
《Effective Java》学习笔记(2)
作者:未知 时间:2005-07-27 22:36 出处:CSDN 责编:chinaitpower
              摘要:《Effective Java》学习笔记(2)

这是第2篇

二。对于所有对象都通用的方法

主要介绍如何正确地改写Object类中的非final方法。

第7条:在改写equals的时候请遵守通用的约定

    改写equals方法所必须遵守的几个约定

1。自反性:X.equals(X)必须返回true

2。对称性:Y.equals(X)返回的必须和X.equals(Y)一致

3。传递性:X.equals(Y),Y.equals(Z)如果返回true的话,那么X.equals(Z)也必须返回true

4。一致性:多次调用X.equals(Y)返回的值应该是一致的

5。非空性:X.equals(null)必须返回false

这里最容易产生错误的是第2和第3条。要保证第2条你必须保证不扩大比较的对象的范围。而第3条产生的问题一般在继承的过程中,子类扩展了父类,增加了新的变量,涉及到面向对象关系理论的一个基本问题,那就是:

要想在扩展一个可实例化的类的同时,既要增加新的特征,同时还要保留equals约定,没有一个简单的方法可以做到这一点。

撰写高质量的equals方法的一些处方或者说告戒:

a.使用"=="检查引用是否为空

b.使用instanceOf检查对象的类别是否正确

c.把实参转换到正确的类型,并保证实际参数中的"关键域"与当前对象中对应的域是否匹配

d.编写完equals之后应该检查是否满足:对称性,传递性,一致性

e.当你改写equals的时候,总要改写hashCode

f.不要企图让equals方法过于聪明,加入太多等价关系比较只会让事情变糟糕

g.不要使equals方法依赖于不可靠的资源

h.不要使equals声明中的Object对象替换为具体的类型对象

不过,你可以用组合代替继承,在新的类中加入一个原有类的对象,而不是继承它,这样就不会遇到保持equals的问题了。

第8条:在改写equals时总是要改写hashCode

    如果不这样做的话,就导致该类无法与所有基于散列值的集合类型一起正常工作,如HashSet,HashMap。一个理想的散列函数应该把一个集合中的不相等的对象均匀的分布到所有可能的散列值上,书中提供了一种方法接近理想状态

1.把某个非0的常整数保存在一个叫result的int型变量中

2。对于对象中的每一个关键域f完成下列步骤

a。为该域计算散列码c:

   i.如果是boolean      f?0:1

  ii.byte,char,shor,int型     (int)f

  iii.long型        (int)(f^(f>>32))

   ivfloat型      Float.floattoIntBits(f)

   v.double型  Double.doubletoLongBits(f)得到一个long型,然后按iii计算

   vi.如果是一个对象引用可以递归调用hashCode()或者计算一个另外的“规范表示”

   vii。如果是一个数组,则把每一个元素当作一个单独的域来处理

b.按公式计算散列码 result=37*result+c;

3。返回result

还一点,一定要包括该类的关键性的变量,不要试图通过排除一个对象的关键部分来获得性能的提高

第9条:总是改写toString()

这一条更多的是为了提供更有价值的信息给使用者,我很少使用这点,惭愧

第10条:谨慎地改写clone()

实现对象的深层拷贝。可以这样认为,clone()方法是另一个构造函数!要编写一个行为正确的clone()方法,特别是对于一些类的内部具有可变的域是相当困难的。首先你必须实现cloneable接口,在clone()方法中调用super.clone(),然后修改任何需要修改的变量。例如,要对上一骗文章的Stack撰写一个正确的clone方法如下

public Object clone() throws CloneNotSupportedException{

     Stack result=(Stack)super.clone();

      result.elements=(Object)elements.clone();

      return result;

}

前提要求elements不是final.

clone()方法的改写是复杂的,甚至是危险的,还有另一种方法来提供拷贝对象的功能,那就是拷贝构造函数。这同样不是C++专有的概念。

例如public Example(Example),你传入一个同类型的对象,然后在这个构造函数中做变量的拷贝就OK了。相比于Cloneable接口的复杂度,这是一个更好的解决办法。

第11条:考虑实现Compareable接口

此接口的实现类似于equals方法,也要保持对称,传递,一致等特性,具体不再介绍,如果你需要对某个类的对象实行排序等算法或者与Collections Framework中的类打交道,你该考虑实现这个接口


关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有