在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的最后一个孩子?