2014-12-28 74 views
3

當在相同的類我有兩個重載方法:編譯錯誤曖昧參考方法使用類型集合

public static <T> void foo(Collection<T> collection, T valueToAppend); 
public static <T> void foo(Collection<T> collection, Collection<T> valueToAppend); 

以下測試應該調用第二種方法:

@Test 
    public void testFoo() { 
    ArrayList ftList = Lists.newArrayList(); 
    List<Double> doubleList = Lists.newArrayList(1.0, 2.0); 
    foo(ftList, doubleList); 
} 

當運行測試我得到以下編譯錯誤:

reference to foo is ambiguous, both method foo(java.util.Collection,T) in path.to.class and method foo(java.util.Collection,java.util.Collection) in path.to.class match.

我在第二個傳遞集合參數爲什麼編譯器不知道 轉到第二種方法?
如果我更改方法簽名並從第一個參數中刪除泛型,我將 不會收到編譯錯誤,爲什麼?

+2

因爲''也可以是'Collection' ..這是一個類似於任何其他類型的類型。 –

+0

Arraylist不是'Collection ' –

+3

不相關,但不應該是'T valueToAppend'? –

回答

3

這裏是我的解釋。當編譯器必須在重載之間進行選擇時,它總是選擇最具體的重載。當您從第一個參數中刪除類型信息時,簽名變爲

public static <T> void foo(Collection collection, T valueToAppend) 
public static <T> void foo(Collection collection, Collection<T> valueToAppend) 

其中的第二個更具體。第一種方法可以接受的任何一對參數都可以被第一種方法接受,因爲任何Collection都是Object。因此,當您去除類型參數時,不會有歧義 - 如果您通過兩個Collection s,則會選擇第二種方法。

但是與類型信息,簽名是這樣的:

public static <T> void foo(Collection<T> collection, T valueToAppend) 
public static <T> void foo(Collection<T> collection, Collection<T> valueToAppend) 

這些簽名也不是比其他更具體。參數new ArrayList<String>()"Foo"將被第一個簽名接受但不是第二個。參數new ArrayList<String>()new ArrayList<String>()將被第二個簽名接受,但不是第一個。

所以如果兩個簽名都適用,就有問題。

您正試圖通過一個原始ArrayList和一個List<Double>。由於您使用的是原始類型ArrayList(你應該永遠不會做),ftList可以通過爲Collection<T>任何T(嘗試它。請嘗試將原料ListList<String>類型的參數的方法。它的工作原理)。因此,您只需要看到doubleList的第二個參數相匹配,兩者均爲超載。它匹配第一個簽名,如果TList<Double>並且匹配第二個簽名,如果TDouble

+0

謝謝詳細的答案。你能解釋爲什麼傳遞一個原始類型ArrayList作爲第一個參數不會自動將定義爲Object? –

+0

@ D.C它將''定義爲Object。這是你的問題。 – Tom

+0

@Tom但如果是對象,那麼我期望簽名看起來像這樣:'public static void foo(Collection collection,Object valueToAppend) public static void boo(Collection collection,Collection valueToAppend)'。但是這些簽名不會導致編譯錯誤。 –

0

因爲第二個參數<T>可能是一個Collection也解釋是混亂無論是Collection<T><T>

0

編譯器無法識別<T>Collection<T>之間