考虑以下课程:
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
)。
为什么?
答案 0 :(得分:10)
您正在呼叫b1.equals(b3)
- b1
是Base
的实例,而不是Sub
的实例,因此无法调用您的覆盖方法。
哎呀,即使b3.equals(b1)
也不会在Sub
上调用任何内容,因为b3
也会引用Base
的实例。
仅b4
和b5
引用Sub
的实例,因此仅 b4.equals(...)
或b5.equals(...)
会调用您的重写方法。此外,由于您在equals
方法中无条件投射,b4.equals(b1)
(例如)会抛出异常,而不是返回false
。
答案 1 :(得分:2)
让我们看看您的代码(在主方法中)如何运行
Base b1 = new Base(1);
: - 创建新的Base(1)对象,引用为b1
。让我们将此Object称为第一个对象。
Base b2 = b1;
: - 创建一个Base类型引用变量并赋值b1
变量,所以b1和b2都指向同一个对象(第一个对象)
Base b3 = b2.foo();
: - 在第一个Base对象中创建一个Base类型引用变量b3.
foo()
方法,它返回一个新的Base对象(第二个对象),在那里它' si属性值=第一个对象>属性值
Base b4 = new Sub(1);
: - 创建新的Sub(1)对象,引用为b4
。让我们将此Object称为第三个对象。
Base b5 = b4.foo();
: - 在第三个对象(Sub)中创建一个Base类型引用变量b5.
foo()
方法,并将其自己的引用作为Base类型返回。 Sub可以将自己的引用作为Base返回,因为Base是它的超类。
b1.equals(b3)
: - 现在你调用了b1
引用的对象的equals方法。 b1
指的是Base
类型对象(第一个对象)。运行Base对象的equals方法。它具有默认的equals方法。 (重写方法位于Sub对象中,而不是Sub对象。)default 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));