我具有以下多态类层次结构,并且想了解使用动态绑定时如何评估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)
为什么在调用非静态函数this
时B.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 "%r" %s %b" resolveHosts="false" />
</Host>
?
答案 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
中。由于运行时知道D
是c
的实例,因此将调用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)
中的实现。