为什么返回4?(继承)



对于这个代码:

public class Demo
{
public static void main(String[] args)
{
System.out.println( new B().m1()  );
}
}
class A
{
int m1() {return m3();}
int m2() {return this.m3();}
int m3() {return 1;}
}
class B extends A
{
int m1() {return super.m1();}
int m3() {return 4;}
int m4() {return m2();}
}

返回4,但我不确定为什么。所以我是这样看的:new B().m1()创建一个B类型的对象并调用B类的m1()方法,this调用A类的super.m1(),它返回m3(),即1。我知道你可以在继承中重写方法,但m1()在类A中显式返回m3(),而不是在类B中,那么为什么返回4和输出而不是1?

Java的实例方法是严格的动态调度。

任何方法调用总是将根据this引用的实际类型将击中该方法的"最具体"版本。

唯一的例外是super.x(),它将调用您的super,但它是一次性的转移。在该方法中执行的任何调用都像往常一样执行动态分派。

:

new B().m1()自然调用B的m1()方法:因为实际实例的真实类型自然是B

该方法将调用A的m1()。A1的m1()代码为:

return m3();

当然是

的缩写
return this.m3();

this在这里是仍然是B的一个实例。因此,应用了动态调度,将调用class Bm3()impl,因此返回4

没有办法避免这种情况,除非重写所有这些方法。

需要考虑的2个重要事项:

  • static方法不做这些事情。
  • 在java中,方法的名称包括参数类型(没有泛型,即擦除)返回类型。所以,如果你有:
class Parent {
void foo(Object o) {}
}
class Child extends Parent {
void foo(String o) {}
}
...
Parent p = new Child();
p.foo("hello!");

将仍然调用父foo,而不是子foo,因为它们是不同的方法。这就是为什么你总是使用@Override当你打算覆盖;这意味着,由于类型不匹配,当您实际上没有覆盖时,您会得到编译器错误。

最新更新