您的位置:首页 > 编程语言 > Java开发

JAVA拾遗 - 如何正确地覆盖equals方法

2016-09-19 11:30 232 查看
本文思想来自于Effective Java第二版 3.1章节,实为阅读总结,如果读者有疑惑的地方强烈建议阅读这个章节。


何时覆盖Equals方法

何时不应该覆盖

覆盖equals方法看上去是一件简单的事情,但是很多覆盖的方法都会导致一些隐性的BUG,最容易避免这些问题的方法就是 不覆盖 equals方法,在这种情况下每个类都只与其自身相等,如果满足以下任何一个条件,就不应该覆盖equals方法

类的每个实例在本质上都是唯一的

对于代表活动实体而不是值的类来说,如Thread等类。Object类提供的equals方法能够实现这些类的正确行为

不关心类是否提供了“逻辑相等”的测试功能

java.util.Random
覆盖了equals,以检查两个Random示例是否产生相同的随机实例,但是设计者并不认为客户需要这些功能,在这种情况下单纯Object的equals方法就足够了

超类已经覆盖了equals方法,而从超类继承过来的equals方法对于子类也是合适的

大多数的Set都实现从AbstructSet继承equals实现,大多数List实现从AbstructList继承equals实现,大多数Map实现从AbstructMap继承equals实现

类是私有的或者是包级私有的,可以确定其equals方法永远都不会调用

在这种情况下应该覆盖其equals方法,以防止其被意外调用。如:

@Override
public boolean equals(Object o) {
throw new AssertionError();//method is never called
}


何时应该覆盖Equals呢?

如果类具有自己特有的“逻辑相等”概念(不同于对象等同的概念),且超类并没有覆盖equals方法以实现期望的行为,我们就应覆盖equals方法。

比如说“值类”的情况。我们在对比值类的时候,单纯想知道其在逻辑上是否相等,而不想了解他们是否指向同一个对象。同时这样也使得这个类的实例可以被用作map的key,或者集合的元素,使得映射或者集合能够表现出预期的行为。

equals方法的特性

equals方法实现了等价关系(equivalence relation):

自反性(reflexive)—>
x != null && x.equals(x) == true


对称性(symmetric)—>
if(x != null && x.equals(y))
可以推出
y.equals(x)


传递性(transitive)—>
x != null && x.equals(y) == true && y.equals(z)
可以推出
x.equals(z)


一致性(consistent)—>对于非null的x、y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用equals返回的一致是true或者一致是false

对于非null的x,
x.equals(null)
返回值一定是false

John Donne说过,没有哪个类是孤立的。你需要不断地把一个类的实例传递给另外一个类的实例,在传递过程中,很多类的都依赖于是否遵守equals约定!

覆盖的注意事项

1.覆盖时总是要覆盖hashCode方法

2.别想着把equals做得太“智能”

3.千万别把equals方法中的Object参数对象替换成其他类型(从Override变成Overload!)

4.在每次覆盖equals方法都逐一审查equals 的五个约定,就能避免很多隐藏的BUG!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: