2010-01-05 51 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