Java方法调用重载逻辑

3
对于下面的代码,为什么会打印出 A, B?我原以为应该是 B, B。 另外,JVM 执行的方法调用是动态评估还是静态评估?
public class Main {
    class A {

    }

    class B extends A {

    }

    public void call(A a) {
        System.out.println("I'm A");
    }

    public void call(B a) {
        System.out.println("I'm B");
    }


    public static void main(String[] args) {

        Main m = new Main();
        m.runTest();
    }

    void runTest() {
        A a = new B();
        B b = new B();

        call(a);
        call(b);
    }

}
3个回答

14

函数重载是由编译器在静态时期决定的,而覆盖则是在执行时期完成的,但这里并不是一个因素。

a 的静态类型是 A,因此第一次方法调用解析到 call(A a)


谢谢,那么什么是动态评估的? - Maxim Veksler
@Maxim Veksler:覆盖 - 这是由目标对象的实际类型决定的,而不是编译时类型。 - Jon Skeet

3

在这种情况下,由于对象的类型为A,因此将调用带有参数A的方法。因此,是的,它是静态确定的。

这是为了避免歧义。您的B也是一个A,但两个方法不能同时调用。


1

BA 的子类。由于您实例化了一个 B,但将其分配给类型为 A 的变量,所有 B 的特定内容都将“丢失”,因此 call(a) 将被分派到 call(A, a) 并打印出 'A'。


这有点误导人。名为a的对象仍然保留着“所有的B特定信息”——例如调用a.getClass().getSimpleName()将返回“B”。正如Jon指出的那样,重载是由引用的类型在编译时确定的。在这个上下文中,编译器并不“知道”a实际上是B的一个实例,因此它将调用编译到call(A a)方法。但是a仍然B的一个实例。 - Andrzej Doyle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接