Java方法调用重载逻辑

Java方法调用重载逻辑,java,jvm,overloading,Java,Jvm,Overloading,对于以下代码,为什么打印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.prin

对于以下代码,为什么打印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);
    }

}
重载由编译器静态确定。重写在执行时完成,但这不是一个因素


a
的静态类型是a,因此第一个方法调用被解析为
call(a)

,因为您的对象是通过其类型
a
知道的,此时将调用带有参数
a
的方法。是的,它是静态确定的


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

B
A
的子类。由于您实例化了a
B
,但将其分配给了类型为
a
的变量,所有
B
细节都将“丢失”,因此
call(a)
将被分派到
call(a,a)
并打印“a”。

谢谢,那么什么是动态计算的呢?@Maxim Veksler:Overriding——这是由目标对象的实际类型而不是编译时类型决定的。这有点误导。名为
a
的对象仍然保留“其
B
的所有细节”-例如,调用
a.getClass().getSimpleName()
将返回“B”。正如Jon指出的,重载是由编译时引用的类型决定的。编译器在此上下文中不“知道”
a
实际上是
B
的实例,因此它编译对
call(a)
方法的调用。但是
a
仍然是
B
的一个实例。