看看来自 Angelika Langer 的"Implementing equals() To Allow Mixed-Type Comparison"。
以下是一些问题的简要说明和可能的解决方案:
平等合同说(其中包括):
它是对称的:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应该返回 true。
这意味着如果您的子类引入新字段并且您将基类的对象(或另一个不覆盖 equals 的子类)与该子类的对象进行比较,您可能会遇到问题。
请勿执行以下操作:
class BaseClass {
private int field1 = 0;
@Override
public boolean equals(Object obj) {
if (obj instanceof BaseClass) {
return field1 == ((BaseClass) obj).field1;
}
return false;
}
}
class BadSubClass extends BaseClass {
private int field2 = 0;
@Override
public boolean equals(Object obj) {
if (obj instanceof BadSubClass) {
return super.equals(obj)
&& field2 == ((BadSubClass) obj).field2;
}
return false;
}
}
因为你得到
BaseClass baseClass = new BaseClass();
BadSubClass subClass = new BadSubClass();
System.out.println(baseClass.equals(subClass)); // prints 'true'
System.out.println(subClass.equals(baseClass)); // prints 'false'
一种可能的解决方案:
将instanceof-check 替换为类比较:
obj != null && obj.getClass() == getClass()
使用此解决方案,BaseClass 的对象永远不会等于任何子类的对象。
如果您在没有 equals 方法的 @Override 的情况下创建另一个 SubClass,则两个 SubClass-objects 可以彼此相等(如果 BaseClass.equals 检查决定如此)开箱即用,但是SubClass-object 永远不会等于 BaseClass-object。
一个好的实现可能如下:
class BaseClass {
private int field1 = 0;
@Override
public boolean equals(Object obj) {
if (obj != null && obj.getClass() == getClass()) {
return field1 == ((BaseClass) obj).field1;
}
return false;
}
}
class GoodSubClass extends BaseClass {
private int field2 = 0;
@Override
public boolean equals(Object obj) {
if (obj instanceof GoodSubClass) {
return super.equals(obj) && field2 == ((GoodSubClass) obj).field2;
}
return false;
}
}
有关更高级的问题及其解决方案,请参阅上述文章。