在我正在阅读的“核心Java卷1 ”一书中,它表示平等不应该与继承一起使用。所以,我有以下示例似乎有问题:
public class Main {
public static void main(String[] args) {
C c = new C("Test", 10);
D d = new D("Test", 10);
if (c.equals(d))
System.out.println("Equal");
else
System.out.println("Unequal");
if (d.equals(c))
System.out.println("Equal");
else
System.out.println("Unequal");
}
}
class C
{
C(String cstr, int cnum) {
str = cstr;
num = cnum;
}
@Override
public boolean equals(Object otherObject) {
// A quick test to see if the objects are identical.
if (this == otherObject) {
return true;
}
// Must return false if the explicit parameter is null
if (otherObject == null)
{
return false;
}
if (!(otherObject instanceof C))
return false;
// Now we know otherObject is a non-null Employee
C other = (C) otherObject;
// Test whether the fields have identical values
return str.equals(other.str) && num == other.num;
}
private String str;
private int num;
}
class D extends C {
D(String cstr, int cnum) {
super(cstr, cnum);
}
}
对于两个对称比较,它返回“等于”,这可能不应该。是否在派生类'D'中缺少另一个equals
方法?如果是这样的话,那么上面的示例代码可能会出现什么问题,如果我根本不使用其他equals
那么?
答案 0 :(得分:4)
如果您希望实例C
和D
不能与!(otherObject instanceof C)
等同替换为otherObject.getClass() != this.getClass()
。这样可以确保只有C
可以与另一个C
相等,只有D
可以与另一个D
相等。
这是否是你想要的取决于几个因素。我的一般经验法则是,拥有一个“开放式”平等类是一个坏主意,“外部用户”(无论对你来说意味着什么)可以添加到它。如果您希望将不同类型的对象比较为相等(并且这种情况非常罕见),则应严格控制层次结构(例如,使用final
类)。
集合(和类似的明确定义的接口)是不同的:这里接口定义了一个非常精确的契约,所有实现类都需要遵循(即ArrayList
如果它们可以等于LinkedList
两者都以相同的顺序包含相同的元素,因为List
接口定义了两个List
s相等的含义。
答案 1 :(得分:4)
该代码有效,因为正如您所说,D
并不会覆盖equals
。我希望本书的重点是D
应覆盖equals
(并且它们都应覆盖hashCode
),因为D
个实例不应该等于C
个实例,因为它们是不同的(尽管是相关的)类型。
请记住,the equals
contract的一个关键方面是对称。对于null
和c
的任何非d
值,如果c.equals(d)
为真,则d.equals(c)
必须为真(并且相反)。虽然这在您当前的代码中是正确的,但它可能不应该是,因为D
和C
是不同的类型。如果D
实例与C
实例真正等效,为什么要D
?