2015-11-01 68 views
11

我有兩個重載方法:foobar重載可變參數數組,選擇方法

//Object[]... vs Integer[]... 
public static String foo(Object[]... args) { return "Object[] args"; } 
public static String foo(Integer[]... args) { return "Integer[] args";} 

//Object... vs Integer[]... 
public static String bar(Object... args) {return "Object args";} 
public static String bar(Integer[]... args) {return "Integer[] args";} 

現在,當我使用它們,如:

Integer[] i = { 5 }; 
System.out.println(foo(i));//Object[]... vs Integer[]... 
System.out.println(bar(i));//Object... vs Integer[]... 

我越來越

Integer[] args 
Object args 

這是一個問題:爲什麼我們有兩個不同的輸出?
Integer[]可以隱式投射到ObjectObject[]

+2

對於那些想玩夏洛克[15.12.2.5。選擇最具體的方法](https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2.5) – Pshemo

+0

您至少應該提及編譯器警告。 –

+0

@Colonel,是的,你可以,是的,你可以。當你嘗試時你會得到一個運行時異常。 –

回答

3

這基本上是編譯器決定調用中所有最具體的方法。

當你調用

System.out.println(foo(i));//Object[]... vs Integer[]... 

它會調用foo(Integer[]... args)

因爲在運行時,JVM代表的調用方法與Integer[][]參數和Object[][] PARAM方法,通過varags規定。因爲使用Integer [] []而不是Object [] []調用方法會更具體。


在後來的聲明,當你調用

System.out.println(bar(i));//Object... vs Integer[]...

它會去bar(Object... args)

再次使用varags,PARAM的類型將對象[],而不是目的[][]。再次編譯器會調用,這將是具有Object... args所述一個最具體的方法。

如果更改按以下刪除varags方法簽名:

//Object... vs Integer[]... 
    public static String bar(Object args) { 

     return "Object args"; 
    } 

    public static String bar(Integer[] args) { 
     return "Integer[] args"; 
    } 

,那麼你會發現,它會調用bar(Integer[] args),因爲它是更具體的方法調用。

所以要按照JLS Subtyping among Array Types更精確,

  • 如果S和T都引用類型,則S []> T []當且僅當S> T.
  • 對象>對象[]

這意味着整數[]的呼叫將要方法由具有整數[] [],而不是對象[] []。 Integer []的調用將被設置爲Object []而不是Integer [] []。

請參閱here選擇最具體的方法。

3

在第一種情況,args來類型實際上是整數[] [],即,您的陣列盒裝成由可變參數另一陣列。編譯器選擇Integer []版本,因爲它是最具體的類型。

在第二種情況下,ARGS == i和是一個Integer []。在這種情況下,編譯器必須選擇將它包裝在一個新的數組中以調用Integer [] ...版本,或者只是將Integer []轉換爲Object []。它選擇了第二個,因爲這是規則。

這個故事的寓意是:不要超載可變參數的方法 - 這是令人困惑的。

+1

你能找到說'這是規則'的規格位嗎? –

+0

我可以......但是OP已經用他的編譯器證明了它:) –

+0

如果你能找到它,我會贊成。我無法破譯它。 –