什么时候重载equals方法?
我们先来看一看equals()方法在Object类中的实现:
public boolean equals(Object obj) {
return (this == obj);
}
在Object类中,equals()方法用于判断两个引用是否指向同一个对象,因此,如果你的目的正是如此,就大可不必费力重载这个方法了.这种方法的实现使用与代表活动实体而不是"值"的类,比如Thread.
因此,需要重载equals()的类就被限制在值类范畴,因为这时候用户不是想判断两个引用是否指向同一个对象,而是想判断这两个引用的值是否"逻辑相等".
但是下面两种情况,即使该类是值类,equals()方法也不需要被重载:
1.实例受控类-------每个值最多只存在一个对象.
2.枚举类
对于上述两种类,判断值相等和判断实例相等实际上是一回事.
重载equals()方法要遵循的四个原则
当我们真正需要重载一个equals()方法时应该如何做呢?java规范里之处equals()重载时要遵守五个原则:
1.自反性(reflexive):即x.equals(x)总是返回true,其实这条很难违反.
2.对称性(symmetic):如果x.equals(y)返回true,那么y.equals(x)也应该返回true,反之亦然.
3.传递性(transitive):如果x.equals(y)返回true,y.equals(z)也返回true,那么x.equals(z)也应该返回true
4.一致性(consistent):如果x.equals(y)返回true,在x和y中的信息不发生改变的情况下,多次调用x.equals(y)都应该返回true.
5.非空性:即x.equals(NULL)永远返回false,没有对象和NULL相等
如何实现高质量的equals()方法?
1.“==”检测和instanceof检测:一个重载的equals()方法通常会在开始时进行一下两项检测
@override
public boolean equals(object o) { //参数类型必须是object,否则就不是重载而是新方法了
if(o == this){ //当比较操作比较昂贵时,值得这么做
return true;
}
if(!o instanceof ClassA){ //确保下面的强制类型转换可以正常进行
return false;
}
ClassA a = (ClassA) o;
//......
}
2.比较类中的“关键”域,避免冗余域的比较
例如两个矩形的长宽相等,那么它的面积自然相等,这是就不要在equals方法中增加比较面积的步骤
3.由于Float.NaN,-0.0f等常量的存在,double和float两种基本类型的比较要使用他们各自的compare()方法,其他基本类型的域可以直接使用“==”比较
4.某些对象引用域包含NULL可能是合法的,此时应采用如下实现
(field == null ? o.field == null : field.equals(o.field));
5.如果数组是关键域,并且每个元素都很重要,那么要使用Arrays.equals方法
6.测试,一定要测试!
编写完成后,一定要测试方法是否满足上面五个原则!!!
其他注意事项
1.重载equals方法后一定要覆盖hashCode方法(后面会讲)
2.不要让equals方法过于智能,过犹不及,我们无法在扩展可实例化类的同时,既增加新的值组件,同时又能满足equals约定,是不可能的。除非愿意放弃面向对象的抽象所带来的优势