2010-01-05 63 views
3

对于下面的代码为什么打印A,B?我期望它打印B,B。 另外,JVM执行的方法调用是动态还是静态评估?Java方法调用重载逻辑

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); 
    } 

} 

回答

14

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

a的静态类型是A,所以第一个方法调用解析为call(A a)

+0

谢谢,那么什么是动态评估? – 2010-01-05 14:05:00

+0

@Maxim Veksler:覆盖 - 由目标对象的* actual *类型决定,而不是编译时类型。 – 2010-01-05 14:05:41

+0

非常感谢Jon。 – 2010-01-05 14:12:56

3

由于此时您的对象已知其类型为A,因此将调用具有参数A的方法。所以是的,这是确定静态

这是为了避免含糊不清。您的B也是A - 但这两种方法不能同时调用。

1

BA的子类。既然你实例化一个B,但将其分配给一个变量类型为A,所有B细节将'丢失',因此call(a)将被分派到call(A, a)并打印'A'。

+0

这有点误导。名为'a'的对象仍然保留“所有的'B'特性” - 例如调用'a.getClass()。getSimpleName()'将返回“B”。正如Jon指出的那样,重载是由编译时的**引用**的类型决定的。编译器在这个上下文中并不知道“a'实际上是'B'的一个实例,所以它编译了对'call(A a)'方法的调用。但'a'仍*是* B的一个实例。 – 2010-01-05 14:14:56