2013-04-27 33 views
4

在下面的代碼導致編譯時間錯誤:(?捕獲#1-的擴展對象)泛型和參數化類型中的Java

的方法中的添加型 List是不適用於 參數(字符串)

代碼:

List<? extends Object> a1 = new ArrayList(); 
a1.add("string"); 

錯誤是在線:

a1.add("string"); 

由於class String從Object繼承而來,爲什麼ref a1不接受String類型?

回答

4

我建議你閱讀這篇文章,http://java.dzone.com/articles/covariance-and-contravariance。 (斜體添加是我的)

綜上所述,我們使用的協方差<? extends Object>當我們只打算採取通用 值出的結構。我們用逆變<? super Object>當我們只打算 把通用值放入結構,我們用一個不變<Object>當我們 打算一舉兩得。

您已定義列表,拿着協變的對象類型,這意味着你可以寫Object o = a1.get(1),但你不能寫a1.add("foo")。如果您希望能夠添加對象,但不是讓他們回來,那麼你就需要這樣定義列表:

List<? super Object> a1 = new ArrayList<>(); 

這有點不幸,在我看來,語言的作者使用的術語extendsuper以表示協變和逆變,特別是在上面的例子中,因爲沒有超類型Object

4

? extends Object的意思是「一些未知類型X,延伸Object」。通過嘗試將String添加到集合中,您基本上聲稱編譯器無法驗證X = String。據編譯器知道,X也可以是Integer或完全不同的東西。

換句話說List<? extends Object>並不意味着「任何延伸Object去」。簡單的List<Object>意味着。

1

List<? extends Object>可用於每種類型的列表。

你怎麼想,那會是安全的,讓它添加任何對象,如果例如

List<? extends Object> a1 = new ArrayList<Integer>(); 
a1.add("string"); 

只能在安全值增加會null因爲它不屬於任何特定的類型。

爲了擺脫這個問題,你可以使用例如List<String> a1 = new ArrayList<String>()List a1 = new ArrayList()