2015-05-10 89 views
2

採取以下代碼:約泛型奇怪的行爲,我

public class Main { 

    public static void main(String[] args) { 
     List<Object> list1 = new ArrayList<Object>(); 
     List<? super Integer> list2 = list1; 
     list2.add(1); 
     list1.add("two"); 
     //list2.add("three"); // will never compile!!. 
     System.out.println("list1: " + list1.toString()); 
     System.out.println("list2: " + list2.toString()); 

    } 

} 

這裏是輸出:

list1: [1, two] 
list2: [1, two] 

,一方面,列表2不允許在對象的add()方法像弦「三」;但另一方面,它引用一個包含對象的列表。

+2

你能澄清一下實際問題是什麼嗎?我假設它是這樣的:「當list2的類型是'?super Integer'時,list2似乎包含一個字符串(在print語句中),特別是給它添加一個字符串爲list2.add(」three「) '不會編譯?「但你真正給出的只是一個觀察。 – alexroussos

+0

你擁有的是一個有效的賦值列表,如果你不考慮它被處理的序列,那麼這個賦值可能看起來很奇怪。在你指定'list2 = list1'時,它是完全有效的,即使在稍後的點你可以通過'list1.add(「three」)添加新條目(因爲它們實際上是一個單獨的列表);'沒有什麼奇怪和不尋常的關於它 –

回答

3

編譯器不關心列表實例接受哪種對象。在字節碼級,任何參考因類型擦除而被接受。它只知道使用特定泛型類型參數化的List類型的兩個變量。這些變量之一可以分配給另一個是被檢查然後被遺忘的東西。

因此,當您嘗試添加"three"時,它會查看list2類型所接受的泛型類型,看到它不匹配並引發編譯錯誤。

至於方案:沒有任何問題。如果要通過變量引用來限制要添加或從列表中刪除的對象,則由您決定。

請注意,無法從變量引用的列表中檢索String而無法進行轉換。

+0

我同意認爲這種事情是*遠*從直覺上講,我不是當前設置與泛型方面的大粉絲。 –

+0

你能解釋爲什麼'list2.add(new Object());'不能編譯,因爲'Object'顯然是'Integer'的超類型?你不應該能夠添加任何超級類型,而只需要_get_一個'Integer'而不需要投射? –

+0

我只能通過[參考另一個問題](http://stackoverflow.com/q/3847162/589259)來解釋這一點。它有點相同,但沒有從'list1'到'list2'的分配。如上所述,這對我來說也不直觀。 –