2015-04-22 142 views
3

我試圖定義一個操作++爲我定製Map類型是這樣的:雙通配符泛型類型錯誤

@Override 
public MutableMap<K, V> $plus$plus(Map<? extends K, ? extends V> map) 
{ 
    HashMap<K, V> copy = this.copy(); 
    map.$plus$plus$eq(map); 
    return copy; 
} 

++=運營商的定義是這樣的:

public void $plus$plus$eq(Map<? extends K, ? extends V> map); 

然而,編譯器在map.$plus$plus$eq(map);行抱怨,出現以下瘋狂錯誤:

The method $plus$plus$eq(Map<? extends capture#10-of ? extends K, 
? extends capture#11-of ? extends V>) in the type 
Map<capture#10-of ? extends K,capture#11-of ? extends V> is not 
applicable for the arguments 
(Map<capture#12-of ? extends K,capture#13-of ? extends V>) 

正如你在這張截圖看到,沒有通過Eclipse的工作提供了,但單獨的解決方案,甚至意義:

Eclipse Marker

我一直在Java泛型相當長一段時間的工作,現在,甚至已經開發我自己的自定義編程類型系統(我目前正在編碼的庫),但我從來沒有像這樣的錯誤。


編輯:有趣的是,鑄造map參數的原始類型(Map)似乎來解決這個問題。

map.$plus$plus$eq((Map) map); 

但是,改變投地(Map<?, ?>)(這是Eclipse的第二個解決方案所做的)會導致類似的錯誤。

+0

你使用什麼編譯器? –

+0

以下哪些類是您的自定義類? Map是java.util.Map嗎? –

+0

Eclipse月神服務版本2(4.4.2),目標兼容性1.8。 – Clashsoft

回答

4

它適用於原始類型Map,但是您失去了類型安全性。不要使用原始類型。它們只存在與Java 1.4及更早版本兼容,但沒有泛型。

它不適用於通配符,因爲編譯器不知道通配符?代表什麼類型的通配符。原因與您爲什麼不能call add() on a List<? extends T>的問題相同。

注意通配符不意味着其中關鍵的類型擴展K和值的類型擴展V你可以使用任何類型的對象。相反,這意味着你有一個映射,其中鍵是一些特定的,但未知的類型K,這些值是一些特定的,但未知的類型V。你不能在這樣的地圖上調用$plus$plus$eq,因爲編譯器不知道確切的類型,所以它不能檢查它們。

原則上,您調用該方法的Map的通配符可能代表與您作爲參數傳遞的Map的通配符不同的類型 - 即使您在此例中可以看到它們必須因爲你在這種情況下使用相同的對象map

可以通過使用類型的參數,而不是通配符的修復:

@Override 
public <KK extends K, VV extends V> MutableMap<K, V> $plus$plus(Map<KK, VV> map) 
{ 
    HashMap<K, V> copy = this.copy(); 
    map.$plus$plus$eq(map); 
    return copy; 
} 
2

下面是也不編譯的簡化示例。

class Foo<T> { 

    void bar(Foo<? extends T> foo) { 
     foo.bar(foo); 
    } 
} 

假設foogoo有型Foo<? extends T>。這意味着foo的類型爲Foo<U>,其中UT的子類型,而goo的類型是Foo<V>,其中V也是T的子類型。你不會指望foo.bar(goo)的工作,因爲V可能不是U的子類型。因此,foo.bar(foo)也不能編譯。這看起來很生氣,因爲foofoo是相同的實例,但參數是否適用僅取決於它們的編譯時間類型。