2012-03-06 206 views
12

這是Java(1.6)Collection接口的一部分:泛型集合

public interface Collection<E> extends java.lang.Iterable<E> { 
    /* ... */ 
    boolean containsAll(java.util.Collection<?> objects);  
    boolean addAll(java.util.Collection<? extends E> es);  
    boolean removeAll(java.util.Collection<?> objects);  
    boolean retainAll(java.util.Collection<?> objects); 
    /* ... */ 
} 

爲什麼addAll<? extends E>removeAll<?>

回答

12

我不知道,我用Google搜索了一下。我得到這個交代在這裏:http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html

複製部分:

的generifed集合API經常被混淆在第一的

一個因素是containsAll()的removeAll(),和中的retainAll的簽名() 。您可能希望測試remove()和的removeAll簽名()是:

interface Collection<E> { 
    public boolean remove(E e); // not really 
    public void removeAll(Collection<? extends E> c); // not really 
} 

但它實際上是:

interface Collection<E> { 
    public boolean remove(Object o); 
    public void removeAll(Collection<?> c); 
} 

這是爲什麼?同樣,答案在於向後兼容性。 x.remove(o)的接口契約是指「如果o包含在x中,則刪除它;否則不做任何事情。」如果x是泛型集合,則o不必與x的類型參數類型兼容。如果的removeAll()被泛型僅是可調用的,如果它的參數是類型兼容的(Collection<? extends E>),則該合法的代碼的某些序列之前泛型將成爲非法,像這樣的:

// a collection of Integers 
Collection c = new HashSet(); 
// a collection of Objects 
Collection r = new HashSet(); 
c.removeAll(r); 

如果上述片段如果removeAll()的簽名要求它的參數是Collection<? extends E>而不是no-op,那麼上面的代碼將不會被編譯(製作ca Collection<Integer>和ra Collection<Object>)。生成類庫的關鍵目標之一是不破壞或改變現有代碼的語義,所以remove(),removeAll(),retainAll()和containsAll()必須用弱類型約束來定義。可能有他們從頭開始重新設計的泛型。

0

的Java通過擦除實現泛型。這些信息僅用於編譯時間。我猜java集合設計者爲了保留與pre-generics java版本的更高的前瞻性兼容性。

+2

這不是他要問的。 – SLaks 2012-03-06 14:16:28

+0

對不起,如果我誤解了。 :( – Nicocube 2012-03-06 15:01:15

0

當您添加一個對象時,它需要是主類型的子類(或子子類等)。當你刪除一個對象時,它會返回它作爲集合的類型。這是行動中polymorphism的一個很好的例子。

0

誰在乎你試圖去除?

添加是別的東西;我們不想在我們的收藏中出現奇怪的東西。

按要求;一個例子:

import java.util.ArrayList; 
import java.util.Collection; 
import java.util.List; 

public class Main { 

    private static class A { 

    } 

    public static void main(String[] args) { 
     Collection<A> collection_A = new ArrayList<A>(); 

     Collection<String> collection = new ArrayList<String>(); 

     // no problem to try and remove things that wouldn't be there in the first place; either way, they are gone afterwards 
     collection.removeAll(collection_A); 

     // we can't allow this; you would end up with things in your collection that don't belong there 
     collection.addAll(collection_A); 
    } 

} 
+0

你可以用一個或兩個具體的例子來說明這個問題嗎? – NPE 2012-03-06 14:16:59

2

當你添加項目到你的集合,你想確保他們確實有一定的類型。

刪除它們時,只刪除集合中的那些。不管他們的類型。

3

<?><? extends E>限制性更小。

從一堆蘋果中取出橙子沒有任何問題; 添加桔子到蘋​​果的集合有很多東西錯誤。

+0

我知道你的意思......有無處不在的水果汁,這兩者永遠不會相處+1 – 2012-03-06 14:19:29

+0

是的,但是因爲沒有辦法*添加*橙色到蘋果的集合,集合不可能包含橙色,所以'removeAll()'不妨採用'',對嗎? – NPE 2012-03-06 14:20:11

+2

@aix:這允許你傳遞一個'Fruit'集合(或甚至是「對象」),並從你的集合中刪除它的所有蘋果。 – SLaks 2012-03-06 14:21:13

7

對於任何包含E類型元素的集合,addAll都必須能夠處理輸入集合,而不僅僅是E,但它的所有子類也是如此。因此<? extends E>。如果沒有這個,你不能將List<Integer>的所有元素添加到List<Number>,這顯然是不對的。*

對於刪除,限制不需要嚴格設置,並且試圖刪除元素一些完全無關的類型的集合。例如。你可以有一個Number的集合,你知道它只包含Integer s,所以將它傳遞給removeAllList<Integer>應該可以正常工作,並且編譯器會禁止這樣做。

請注意,根據實施情況,according to the JavadocremoveAll可能會隨意拋出ClassCastException

*背後的原因是在Java中,泛型是不變量。有關更多詳細信息,請參閱this thread

0

一個簡單的例子來說明說了些什麼:

public class Test { 

    public static void main(String[] args) { 
     List<String> l = new ArrayList<String>(); 
     System.out.println(l.remove(new Object())); //false 
     System.out.println(l.contains(new Object())); //false 
//  l.add(new Object()); // does not compile 
    } 

} 
0

要刪除不需要的限制,所以只有<?>,但同時增加了我們要檢查,然後添加類型安全,所以中的addAll是有限制的<? extends E>

0

使用addAll你希望能夠添加屬於泛型類型的子類型的所有元素。這包括將List<String>的所有元素添加到List<Object>。我們使用? extends E接受任何包含存儲在此集合或任何子類型中的類型的Collection。

boolean addAll(java.util.Collection<? extends E> es); 
List<Number> numbers = ...; 
List<Integer> integers = ...; 
numbers.addAll(integers);//works  

boolean addAll(java.util.Collection<E> es); 
numbers.addAll(integers);//does not work E != Integer 

我們不能使用?因爲這將消除由仿製藥提供的任何擔保。

boolean addAll(java.util.Collection<? extends E> es); 
List<Number> numbers = ...; 
List<Integer> integers = ...; 
List<String> strings = ...; 
numbers.addAll(integers);//works 
numbers.addAll(strings);//error 

boolean addAll(java.util.Collection<?> es); 
numbers.addAll(strings);//works - now we have strings in our Number collection 

我們可以使用?刪除,因爲試圖從編號列表中刪除字符串不會影響List<Number>對象。

boolean removeAll(java.util.Collection<?> objects); 
List<Objects> objects = ...; 
List<Integer> integers = ...; 
List<Number> numbers = ...; 
numbers.removeAll(objects);//works 
numbers.removeAll(integers);//works 

boolean removeAll(java.util.Collection<? extends E> objects); 
numbers.removeAll(objects);//does not work 
numbers.removeAll(integers);//works 

boolean removeAll(java.util.Collection<? super E> objects); 
numbers.removeAll(objects);//works 
numbers.removeAll(integers);//does not work