在java中,类型为superclass的对象上的cast返回类型为subclass的对象
为了理解静态绑定和动态绑定之间的区别,我实现了以下代码:在java中,类型为superclass的对象上的cast返回类型为subclass的对象,java,binding,casting,subclass,superclass,Java,Binding,Casting,Subclass,Superclass,为了理解静态绑定和动态绑定之间的区别,我实现了以下代码: 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
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
(和超类)中查找名为met
的方法,该方法具有与A
兼容的参数(参数的编译时类型)。重载解析发现答案是:
int met(A a)
这是在编译时确定的签名。但是,该方法的实现是在执行时根据方法调用的执行时目标确定的。这里的类型是C
,因为this
是对C
实例的引用。(对C
的实例调用f
方法)
现在
C
不会覆盖int-met(A)
,但是B
(它的超类)会覆盖它-所以这就是所使用的实现。B
也重写met(B)
和met(C)
并不重要,因为编译器已经确定调用的是met(A)
方法。这是两个问题,代价是一个问题。(1) 为什么我们要从类B获得实现,以及(2)为什么我们要获得参数类型为A的方法版本
对于问题(1),需要记住的是,当您强制转换对象或将其分配给类型不同的变量时,对象的类不会改变。因此在您的示例中,this
的类始终是C
,因为这是您创建的。类C
从类B
继承它的met(A)
版本,因为它没有自己的版本,并且类B
已经覆盖了类A
中的版本。这就是多态性的意义所在——方法的版本取决于调用它的对象的类,而不是用来调用它的表达式的类型
对于问题(2),Java的一个小怪癖是在编译时评估方法签名。因此编译器看到您正在将类型为
A
的表达式传递到方法中,因此它选择签名met(A)
。因为这个决定是在编译时做出的,所以参数的实际类没有任何区别——编译器已经根据表达式的类型选择了方法。换句话说,Java不提供方法参数的多态性。一年中是否有更好的时间开始学习Java?为什么不?你预计会发生什么B
覆盖了该函数。没有什么不适合开始学习Java:)是的,它覆盖了它,但是转换是针对A的,而不是针对B的。答案是它在继承线上是自下而上的吗?换句话说,当我对超类a进行转换时,需要a的最后一个孩子?