具有多态性和运行时绑定的“ this”关键字的行为

时间:2019-02-02 14:39:43

标签: java inheritance polymorphism

我具有以下多态类层次结构,并且想了解使用动态绑定时如何评估this关键字。

public class A {
  void f(C c) {}
}

public class B extends A {
  void f(C c) {
    System.out.println("B.f(C)");
    c.f(this);
    C.g(this);
  }
}

public class C {
  static void g(A a) { System.out.println("C.g(A)"); }
  static void g(B b) { System.out.println("C.g(B)"); }
  void f(A a) { System.out.println("C.f(A)"); }
  // void f(B b) { System.out.println("C.f(B)"); }
}

public class D extends C {
  void f(A a) { System.out.println("D.f(A)"); }
  void f(B b) { System.out.println("D.f(B)"); }
}

public static void main(String[] args) {
  A a = new B();
  C c = new D();
  a.f(c);
}

注释掉方法C.f(B b)之后,主要方法将打印:

B.f(C)
D.f(A)
C.g(B)

为什么在调用非静态函数thisB.f(C c)方法中的A关键字被评估为f,而在调用非静态函数B时为什么被评估为g静态函数C.f(B b)

此外,我还观察到,如果取消注释方法B.f(C) D.f(B) C.g(B) ,输出将变为:

this

在这种情况下,为什么对于非静态和静态方法,B关键字的类型被评估为<Host name="hackeru.net" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Alias>www.somedomain.net</Alias> <Context path="" docBase="SomeApp" debug="0" privileged="true" /> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b" resolveHosts="false" /> </Host>

1 个答案:

答案 0 :(得分:2)

有决定要调用哪些方法时是两个步骤。一个步骤(哪个重载?)在编译时发生,另一步骤(哪个实现?)在运行时发生。


C.f(B b)已将案例注释掉

,编译器将执行第一步骤中,确定哪些过载调用。 c.f只有一个重载:

void f(A a) { System.out.println("C.f(A)"); }

因此,编译器选择了该选项。 this的编译时类型为B,因此可以隐式转换为A

为什么不编译器看到f(B b)在方法D?因为编译器不知道c是的真正的的D,所以它只会看在C类的实例,因为{{1} }的编译时间类型为c

在运行时,发现C有两种实现-一种在类f(A a)中,一种在类C中。由于运行时知道Dc的实例,因此将调用D

D.f(A a)的情况下取消注释

这个时候,编译器发现的两个重载C.f(B b)调用:

空隙F(A中的){的System.out.println( “C.f(A)”); }   void f(B b){System.out.println(“ C.f(B)”); }

,编译器会选择具有最具体的方法参数。 “最具体”是指一个类型是最远沿着继承树。这意味着将选择c.f

在运行时,将以与第一种情况相同的原因调用f(B b)中的实现。