为了理解静态绑定(bind)和动态绑定(bind)的区别,我实现了以下代码:
class A {
int met(A a) {
return 0;
}
int met(B b) {
return 1;
}
int met(C c) {
return 2;
}
}
class B extends A {
int met(A a) {
return 3;
}
int met(B b) {
return 4;
}
int met(C c) {
return 5;
}
}
class C extends B {
int f() {
return ((A)this).met((A)this);
}
}
public class Test {
public static void main(String[] args) {
C x = new C();
System.out.println(x.f());
}
}
我得到的结果是 3,但我不明白为什么,因为第一次转换为 A。
最佳答案
那么,让我们看看这个调用:
((A)this).met((A)this);
相当于:
A target = this;
A argument = this;
target.met(argument);
因此,对于最后一行,编译器根据所涉及的编译时类型查找签名 - 它将在A
(和父类(super class))中查找一个名为 met
的方法,其参数与 A
(参数的编译时类型)兼容。重载解析发现答案是:
int met(A a)
这是在编译时确定的签名。但是,该方法的实现是在执行时根据方法调用的执行时目标确定的。该类型在这里是 C
- 因为 this
是对 C
实例的引用。 (f
方法在 C
的实例上调用。)
现在 C
不会覆盖 int met(A a)
,但是 B
(它的父类(super class))会覆盖 - 所以这就是实现用过的。 B
也 覆盖 met(B b)
和 met(C c)
并不重要,因为编译器已经确定正在调用的是 met(A a)
方法。
关于java - 对父类(super class)类型的对象进行强制转换在 Java 中返回子类类型的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27711133/