通用集合

Pau*_*zie 13 java generics

这是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);
    /* ... */   
}
Run Code Online (Sandbox Code Playgroud)

为什么addAll必须<? extends E>同时removeAll具有<?>

Nis*_*ant 12

我不知道,我用Google搜索.我在这里得到了这个解释:http://www.ibm.com/developerworks/java/library/j-jtp01255/index.html

复制零件:

通常令人困惑的generifed Collections 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
}
Run Code Online (Sandbox Code Playgroud)

但实际上是这样的:

interface Collection<E> { 
  public boolean remove(Object o);  
  public void removeAll(Collection<?> c);
}
Run Code Online (Sandbox Code Playgroud)

为什么是这样?同样,答案在于向后兼容性.x.remove(o)的接口契约意味着"如果o包含在x中,则将其删除;否则,不执行任何操作." 如果x是泛型集合,则o不必与x的类型参数类型兼容.如果removeAll()被广泛化为只有在其参数是type-compatible(Collection<? extends E>)时才可调用,那么在泛型之前合法的某些代码序列将变为非法,如下所示:

// a collection of Integers
Collection c = new HashSet();
// a collection of Objects
Collection r = new HashSet();
c.removeAll(r);
Run Code Online (Sandbox Code Playgroud)

如果上面的片段以明显的方式进行了生成(制作ca Collection<Integer>和ra Collection<Object>),那么如果removeAll()的签名要求其参数为a Collection<? extends E>而不是no-op ,则上述代码将无法编译.生成类库的一个关键目标是不破坏或更改现有代码的语义,因此必须使用比它们更弱的类型约束定义remove(),removeAll(),retainAll()和containsAll()他们可能已经从头开始重新设计了仿制药.


Pét*_*rök 7

对于包含类型元素的任何集合E,addAll必须能够处理输入集合,而不仅仅是E它的所有子类.因此<? extends E>.如果没有这个,你就无法将a的所有元素添加List<Integer>到a中List<Number>,这显然是不对的.*

为了移除,限制不需要如此严格地设置,并且试图移除一些完全不相关类型的集合的元素没有害处.例如,你可以有集合NumberS,哪些您知道,它仅包含IntegerS,所以将它传递给removeAllList<Integer>应该可以正常工作,这将是愚蠢的编译器来禁止这一点.

请注意,根据Javadoc,removeAll可以选择抛出一个ClassCastException,具体取决于实现.

*背后的原因是在Java中,泛型是不变的.有关更多详细信息,请参阅此线程.