2014-10-03 24 views
5

請參閱該Java類呼叫似乎模棱兩可,但意想不到的輸出完美運行

class Demo 
{ 
    public static void a(String s) 
    { 
     System.out.println("string called"); 
    } 
    public static void a(Object a) 
    { 
     System.out.println("Object called"); 
    } 
    public static void main(String...asrgs) 
    { 
     a(null); 
    } 
} 

這段代碼的輸出是「字符串名爲」但我不能夠理解編譯器是如何能夠與解決對象字符串

此外,檢查該代碼段

class Demo 
{ 
    public static void a(String s) 
    { 
     System.out.println("string called"); 
    } 
    public static void a(Integer n) 
    { 
     System.out.println("number called"); 
    } 
    public static void a(Object a) 
    { 
     System.out.println("Object called"); 
    } 
    public static void main(String...asrgs) 
    { 
     a(null); 
    } 
} 

在這裏我們得到了有關曖昧通話編譯時錯誤(這是相當明顯)。 對此有什麼好的解釋?

+0

第一個或第二個解釋?如果可能的話,兩者都是 – 2014-10-03 07:25:03

+1

:) – Gagan93 2014-10-03 07:27:00

回答

5

答案在於JLS的§15.12.2

第二步搜索在用於部件的方法的一步驟中確定的類型。此步驟使用方法的名稱和參數表達式來定位既可訪問又適用的方法,即可以在給定參數上正確調用的聲明。

可能有多個這樣的方法,在這種情況下最具體的一個被選中。最具體方法的描述符(簽名加返回類型)是在運行時用來執行方法分派的方法。

(我的重點)

...和§15.12.2.5,它上面的部分是指,具有特異性規則的全部細節,而且這個方便的總結:

非正式的直覺是,如果任何由第一個方法處理的調用都可以傳遞給另一個,而沒有編譯時錯誤,那麼其中一種方法比另一種更具體。

在你的第一個例子,a(String)a(Object)更具體,所以編譯器知道哪一個使用,是幸福的。在第二個例子中,兩個a(String)a(Integer)a(Object)更具體的,但無論是適用於null,他們是在不同的譜系(StringString > ObjectIntegerInteger > Number > Object),創造了編譯器抱怨不確定性。

如果他們在相同的沿襲,不會有歧義,因爲會有一個適用的最具體的選項。例如:

class Base { 
} 
class Child extends Base { 
} 
class GrandChild extends Child { 
} 
public class Example { 

    public static final void main(String[] args) { 
     a(null); 
    } 

    public static void a(Base b) { 
     System.out.println("Base"); 
    } 

    public static void a(Child b) { 
     System.out.println("Child"); 
    } 

    public static void a(GrandChild b) { 
     System.out.println("GrandChild"); 
    } 
} 

,打印"GrandChild",因爲同時兼具a(Child)a(GrandChild)a(Object)更具體,a(GrandChild)a(Child)更具體。

相關問題