【问题标题】:overridden equals method doesn't get called重写的 equals 方法不会被调用
【发布时间】:2014-07-04 10:54:26
【问题描述】:
考虑以下类:
public class Base {
protected int i = 0;
public Base(int i) {
this.i = i;
}
public Base(Base b) {
this(b.i);
}
public Base foo() {
return new Base(this);
}
}
public class Sub extends Base {
public Sub(int i) {
super(i);
}
public Sub(Sub s) {
super(s.i * 2);
}
public Base foo() {
return this;
}
@Override
public boolean equals(Object o) {
return ((Sub) o).i == this.i;
}
public static void main(String[] args) {
Base b1 = new Base(1);
Base b2 = b1;
Base b3 = b2.foo();
Base b4 = new Sub(1);
Base b5 = b4.foo();
System.out.println(b1.equals(b3));
}
}
打印结果为false。我注意到被覆盖的方法equals(Object o) 永远不会被抓住,我当然怀疑这是问题所在(否则它会打印true)。
为什么会这样?
【问题讨论】:
标签:
java
oop
inheritance
overriding
【解决方案1】:
您正在调用 b1.equals(b3) - b1 是 Base 的实例,而不是 Sub 的实例,因此无法调用您的覆盖方法。
哎呀,即使b3.equals(b1) 也不会在Sub 上调用任何东西,因为b3 也指的是Base 的一个实例。
只有b4 和b5 引用Sub 的实例,所以只有 b4.equals(...) 或b5.equals(...) 会调用您的重写方法。此外,由于您在 equals 方法中无条件强制转换,b4.equals(b1)(例如)将抛出异常而不是返回 false。
【解决方案2】:
让我们看看你的代码(在 main 方法中)是如何运行的
Base b1 = new Base(1); :- 创建新的 Base(1) 对象,引用为 b1。让我们将此对象称为第一个对象。
Base b2 = b1; :- 创建一个Base类型引用变量并赋值b1变量,所以b1和b2都引用同一个对象(第一个对象)
Base b3 = b2.foo(); :- 在调用第一个 Base 对象时创建一个 Base 类型引用变量 b3. foo() 方法并返回一个新的 Base 对象(第二个对象),其中 i 属性值 = 第一个对象的 i 属性值
Base b4 = new Sub(1); :- 创建新的 Sub(1) 对象,引用为 b4。让我们将此对象称为第三个对象。
Base b5 = b4.foo(); :- 创建一个基类型引用变量b5. foo() 调用第三个对象(Sub)中的方法,并将其自己的引用作为基类型返回。 Sub 可以将自己的引用作为 Base 返回,因为 Base 是它的超类。
b1.equals(b3) :- 现在你已经调用了 b1 引用的对象的 equals 方法。 b1 指的是 Base 类型的对象(第一个对象)。运行 Base 对象的 equals 方法。它具有默认的 equals 方法。 (被覆盖的方法在子对象中,这不是子对象。)默认的equals方法检查它们的哈希码是否相同。 b1 是第一个对象,b3 是第三个对象。所以 b1 和 b3 不相等。
所以输出应该是false。
这里没有发生任何压倒一切的事情。
如果你改变代码如下,你可以得到覆盖输出
Base b1 = new Sub(1);
Base b3 = b1.foo();
Base b4 = new Sub(1);
Base b5 = b4.foo();
System.out.println(b4.equals(b3));