【Effective Java 10.1】覆盖 equals 时请遵守通用约定
1. 不需要覆盖 equals 方法的情况
覆盖 equals 方法看起来很简单,但是有许多覆盖方式会导致错误,并且后果非常严重。最容易避免这类问题的办法就是不覆盖 equals 方法,在这种情况下,类的每个实例都只与其自身相等。以下情况不需要覆盖 equals 方法:
- 类的每个实例本质上都是唯一的:对于代表 “活动实体” 而非 “值” 类,例如
Thread。 - 类没有必要提供 ”逻辑相等“ 的测试功能:例如,
java.util.regex.Pattern可以覆盖equals,以检查两个Pattern实例是否代表同一个正确表达式,但是设计者并不认为客户需要或者期望这样的功能。在这类情况之下,从Object继承得到了equals实现已经足够了 - 超类已经覆盖了 equals,超类的行为对于这个类也是合适的。例如,大多数的
Set实现都从AbstractSet继承equals实现,List实现从AbstractList继承equals实现,Map实现从AbstractMap继承equals实现。 - 类是私有的,或者是包级私有,可以确定它的 equals 方法永远不会被调用。
2. 需要覆盖 equals 方法的情况
对于大部分 ”值“ 类对象都需要覆盖 equals 方法。例如 Interger 或 String。有时甚至需要同时覆写 hashCode 方法。但有一种值类不需要覆盖 equals 方法,即实例受控 ”确保对象只存在一个“(如单例对象,枚举类)
3. 覆盖 equals 方法时的约定
- 自反性(reflexive):对于任何非 null 的引用值。
x.equals(x)始终为真 - 对称性(symmetric):对于任何非 null 的引用值
x,y。当且仅当y.equals(x)返回true时,x.equals(y)必须返回true - 传递性(transitive):对于任何非 null 的引用值
x,y和z。如果x.equals(y)返回true时,且y.equals(z)也返回true,则x.equals(z)也必须返回true - 一致性(consistent):对于任何非 null 的引用值
x、y,只要equals的比较操作在对象中所有的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者一致地返回false - 对于任何非 null 的引用值
x,x.equals(null)必须返回false
如果违反了这些规定,就会发现程序将会表现得不正常,甚至崩溃,而且很难找到程序的 Bug 所在。
浙公网安备 33010602011771号