2015-06-30 77 views
16

簡單的問題,奇怪的結果。我有兩個類AB擴展類的重載方法

public class A 
{ 
    protected int num; 

    public A(int n) 
    { 
     num = n; 
    } 

    public boolean f(A a) 
    { 
     return num == a.num * 2; 
    } 
} 

public class B extends A 
{ 
    public B(int n) 
    { 
     super(n); 
    } 

    public boolean f(B b) 
    { 
     return num == b.num; 
    } 
} 

爲什麼y1.f(y2)呼叫f()方法A,而不是在B

A y1 = new B(10); 
B y2 = new B(10); 

System.out.println(y1.f(y2)); 

難道不應該叫f()B作爲BA更具體?

回答

32

爲什麼y1.f(y2)在A中而不是在B中調用f()方法?

因爲編譯時間類型y1A

超載在編譯時進行......你調用該方法的對象的執行時類型僅適用於覆蓋相關。

所以編譯器選擇方法f(A),因爲它是唯一的f方法,它知道它可以調用y1(並且檢查它適用於參數列表)。該方法在B中未被覆蓋,因此在執行時調用A中的隱含法。

作爲一個有着天壤之別例如,考慮下面的代碼:

Object x = "foo"; 
int length = x.length(); 

這甚至不會編譯,因爲Object不包含length()方法。 String呢,但編譯器並沒有考慮到這一點,因爲x的編譯時間類型是Object,而不是String - 儘管我們可以知道在執行時,x的值將引用String對象。

+0

儘管@ JonSkeet的回答總是不容置疑的,只是也支持這個字節代碼..你也可以檢查什麼方法正在通過,你可以看到編譯代碼爲'(y1.f(y2)) '當你看到字節碼 '25:invokevirtual#27 // Method com/package1/Af:(Lcom/p ackage1/A;)Z' –