2012-03-06 121 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