`
href
  • 浏览: 7795 次
  • 性别: Icon_minigender_1
  • 来自: 福建
最近访客 更多访客>>
社区版块
存档分类
最新评论

对于所有对象都通过的方法

阅读更多
第7条:在改写equals的时候请遵守通用约定
在改写equals方法的时候,你必须要遵守通过约定
1.自反性:对于任意的引用值x,x.equals(x)一定为true
2。对称性:对于任意的引用x和y,当且仅当y.equals(x)返回true时,x.equal(y)也一定返回true
3.传递性:对于任意的引用值x,y,z如果x.equal(y)返回为true,y.equal(z)返回true,那么x.equal(z)也一定返回为true
4.一致性:对于任意的引用值x和y,如果用于equals比较对像信息没有被修改的话,那么多次调用x.equals(y),要么一致返回true,要么一致的返回false
5.对于任意的非空引用值x,x.equal(null)一定返回false

下面是equals方法的一个处方
1.使用==操作检查实参是否为指向对象的一个引用。如果是的话则返回true
2.使用instanceof操作检查实参是否为正确的类型。如果不是的话返回false
3.把实参转化到正确的类型。
4.对于该类中每一个关键域,检查实参种的域与当前对象对应的域值是否匹配。

域的比较顺序可能影响到equals方法的性能,为了获得最佳的性能,最先进行比较的域应该是最有可能不一致的域或者是比较开销最低的域。
5.当你编写完成了equals方法之后,应该问自己三个问题,它是否是对称的,传递的,一致的
8.当你改写equals的时候,总要改写hashcode
9.不要企图让equal方法过于聪明
10.不要使equals方法依赖于不可靠的资源
11.不要将equals声明中的object对象替换成其他的类型
public boolean equals(MyClass o){}
该方法为重载而不是重写

第8条:改写equals时候总要改写hashcode
1.在一个应用程序执行期间,如果一个对象的equals方法做的比较所用到的信息没有被修改的话,那么该对象调用hashcode方法多次,它必须始终如一的返回同一个整数。
2.如果两个对象equals(Object)方法是相等的,那么调用这两个对象中任何一个对象的hashcode方法必须产生同样的整数结果。
3.如果两个对象根据equals方法是不相等的,那么调用这两个对象中任何一个对象的hashcode方法,不要求必须产生不同的整数结果,然而,程序员应该意识到这样的事实,对于不相等的对象产生截然不同的整数结果,有可能提高散列的性能。

一个好的散列函数通过倾向于 为不相等的对象产生不相等的散列码
处方:
1.把某个非零常数值,比如17,保存在一个叫result的int类型的变量
2。对于对象中的每一个关键域(指equal方法中考虑的每一域),完成下面步骤
a。为该域计算int类型的散列玛
i:如果该域是boolean类型则计算(f?0:1)
ii:如果是byte,char,short或则是int类型,则计算(int)f
iii:如果是long类型,则计算(int)(f^(f>>>32))
iv:如果是flot类型,则计算Float.floatToIntBits(f)
v:如果是double类型,则计算Double.doubleToLongBits(f)得到long类型,然后按照步骤2,a,iii 对long类型计算算列
vi:如果该域是一个对象的引用,并且该类是equals方法通过递归调用equals的方式比较这个域,则同样对这个域递归调用hashcode。
vii:如果该域是一个数组,则把每个元素当做单独的域来处理。

b:按照下面的公式,把步骤a中计算得到的散列玛c组合到result中
result=37*result+c

public int hashcode(){
  int result=17;
  result=37*result+c1;
  result=37*result+c2;
  result=37*result+c3;

}

不要试图从散列计算中排除掉一个对象的关键部门以提高性能。

第9条:总要改写toString

第10条:谨慎的改写clone
cloneable接口的目的是作为对象的一个mixin接口,表明这样的对象允许克隆。不幸的是,它并没有成功的表达这个目的,其中主要的缺陷在于,它缺少一个clone方法,object的clone方法是被保护的,如果不借助于映像机制,则不能仅仅因为一个对象实现了cloneable,就可以调用clone方法。即是是映像调用也可能会失败,因为病不保证该对象一定具有可反问的clone方法。
既然cloneable并没有包含任何方法,那么它到底做了什么呢?它决定了object中受保护的clone方法的实现行为:如果一个类实现了cloneable,则object的clone方法返回该对象的逐域拷贝,否则抛出cloneNotSupportedException
为了实现cloneable接口,使它对一个类确实产生了效果,由此得到一种语言本身之外的机制,无须调用构造函数就可以创建一个对象。

clone方法的通用约定是非常弱的
一般的含义是,对于任何对象x表达式
x.clone()!=x 将会返回true
x.clone().equals(x) 将会返回true
x.clone().getClass()==x.getClass()将是返回true,但是这些都不是绝对的要求

拷贝一个对象往往会导致创建一个对象的新实例,但同时也会要求拷贝内部的数据结构,这个过程中没有调用构造函数

clone结构与指向可变对象的final域的正常用法是不兼容的

第11条:考虑实现Comparable接口
compareTo方法在Object中并没有被声明。相反,它是java.lang.Comparable接口中唯一的方法:compareTo方法允许进行简单的相等比较,也允许执行顺序比较。
如果你正在编写一个值类,它具有非常明显的内在排序关系,比如按字符表顺序,按数值顺序或者按年代顺序,那么你几乎总是应该考虑现实该接口。

Compareable规范:
将当前这个对象与指定对象进行顺序比较。当该对象小于,等于或者大于指定对象的时候,分别返回一个负整数,零或者正整数。如果由于指定对象的类型而使得无法进行比较,则抛出ClassCastException异常。

依赖于比较关系的类包括有序集合类TreeSet和TreeMap,以及工具类Collections和Arrays,他们内部包含有搜索和排序算法。

如果你想为一个实现了compareable接口的类增加一个关键特性,请不要扩展这个类,而是编写一个不相关的类,其中包含一个域,其类型是第一个类,然后提供个视图返回这个域。这样做,你既可以自由的在第二个类上实现compareTo方法,同时也允许客户在必要的时候,把第二个类的实例当做第一个类的实例来看待。

例如:考虑BigDecimal类,它的compareable方法与equals不一致。如果你创建了个hashset,并加入一个new BigDecimal("1.0") 和一个new BigDecimal("1.00")。则这个集合将包含两个元素,因为两个新加入到集合中的BigDecimal实例通过equals方法来比较是不相等。然而如果你是使用TreeSet而不是hashset,则集合中只包含一个元素,因为这两个实例是通过compareTo方法进行比较是相等的。


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics