2011-02-23 70 views
3

我對以下示例(更確切地說,使用一個特定行)存在一些問題。下面的代碼(如下問題之後):Java多態 - 具體示例

public class Up 
{ 
    public void cc(Up u) {System.out.println("A");} 
    public void cc(Middle m) {System.out.println("B");} 
} 

public class Middle extends Up 
{ 
    public void cc(Up u) {System.out.println("C");} 
    public void cc(Down d) {System.out.println("D");} 
} 

public class Down extends Middle 
{ 
    public void cc(Up u) {System.out.println("E");} 
    public void cc(Middle m) {System.out.println("F");} 
} 

public class Test 
{ 
    public static void main(String... args) 
    { 
     Up uu = new Up(); 
     Up pp = new Middle(); 
     Down dd = new Down(); 

     uu.cc(pp); // "A" 
     uu.cc(dd); // "B" 
     pp.cc(pp); // "C" 
     pp.cc(dd); // "B" 
     dd.cc(pp); // "E" 
     dd.cc(dd); // "D" 
    } 
} 

現在uu.cc(pp);uu.cc(dd);是很明顯的,因爲UU是Uppp的實例「看起來像」一個Up藏漢(在編譯時)。對於dd最合適的方法是cc(Middle m),因爲dd是從Middle繼承的Down的實例。

我遇到的最多問題是pp.cc(dd);dd.cc(dd)。 對於在編譯時或運行時確定何時以及如何確定這些方法,我確實有點困惑。 如果有人能幫助我理解,我會很高興。

回答

5

基本上,該方法簽名被選擇以基於編譯時間類型所涉及的表達式的編譯時間,並且實施被選擇在執行時,基於實際執行只是目標的的方法。

因此在編譯時,pp.cc(dd)試圖找到匹配Up.cc(Down)。最具體的匹配是Up.cc(Middle),所以這就是編譯後的代碼。現在在執行時間,執行那將是Up.cc(Middle),因爲Middle不覆蓋該方法簽名。因此它打印「B」。

現在在編譯時,dd.cc(dd)試圖找到Down.cc(Down).比賽有兩個相關的選擇在這裏 - 無論是Middle.cc(Down)其中參數完全匹配,或Down.cc(Middle)其中目標類型完全匹配。編譯器更喜歡Middle.cc(Down)。在執行時,該方法在Down中沒有被覆蓋,所以它打印出「D」。

重載分辨率規範的相關位是15.12,特別是15.12.2 - determining the method signature

0

pp.cc(dd);編譯器必須在屬於pp類型Up的方法之間進行選擇。最適合的是cc(Middle m)。您不要在Middle中覆蓋此方法,因此運行時將調用Up方法。

dd.cc(dd)的編譯器選擇在屬於DownMiddleUp因爲ddDown方法之間。 Middle的方法cc(Down)dd的類型完全匹配並被選中。

因此,編譯時選擇是基於變量的聲明類型和最合適的方法簽名。然後正常的覆蓋規則應用運行時