2014-03-04 110 views
0

假設我們有2個不同的列表。列表泛型協變

列表1可以接受任何Number參數(包括int,double,float和Number的子類的其他所有內容)。

List<Number> l1 = new ArrayList(); 

因此,這樣做的作品非常好。

l1.add(123); 
    l1.add(123.3456); 

List 2 extends Number。問題是我不能添加任何東西,我不明白爲什麼。另外,爲什麼我會需要一個列表<?擴展Something>而不是僅僅創建一個層次最高的類的列表,可以存儲任何子類(如列表1)?

List<? extends Number> l2 = new ArrayList(); 
    l2.add(123); //Error, although Integer is a subclass of Number 
    l2.add(new Integer(123)); // Wrappers don't work either 
    l2.add(123.456); //Error again 
+0

查找術語PECS(生產者延伸,超級消費者)。 Java方差「聲明」是在使用時完成的,而不是類定義時間 –

回答

5

與主叫如add具有與一個? extends通配符一類的通用參數的方法的問題是,確切的類型是未知的給編譯器。它可以是List<Number>List<Integer>List<Double>List<BigInteger>。編譯器必須保留泛型的類型安全性,如果它允許這樣的調用,類型安全性將不會被保留。您不應該被允許將Double添加到可能是List<Integer>的列表中。

這樣的? extends上限綁定通配符本身是有用的方法參數,其中確切的類型無關緊要;它只是很重要的,這是約束(在這種情況下,Number)或更低。

public void foo(List<? extends Number> list) { 
    for (Number n : list) { 
     // do something with some kind of Number, don't care which 
+0

它給出了一個編譯錯誤,默認爲novariance。任何想法? – MMK

1

通配符不用於修改列表,僅用於處理已包含在列表中的元素。如果您創建列表或向列表添加元素,則必須知道列表中包含哪些元素。

2

?是編譯器未知的通配符。它可以是從數字派生的任何類型的實例。泛型是爲了類型安全的確切目的而實現的,並且由於類型進入是未知的,所以這是行不通的。