通用集合

2022-09-04 08:02:36

这是 Java (1.6) 集合接口的一部分:

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<?>


答案 1

我不知道,我用谷歌搜索。我在这里得到了这个解释: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
}

但事实上它是:

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);

如果上面的片段以明显的方式被归纳(使c a和r a),那么如果demoveAll()的签名要求其参数是a,而不是no-op,则上面的代码将无法编译。生成类库的关键目标之一是不破坏或更改现有代码的语义,因此必须使用比从头开始重新设计泛型时更弱的类型约束来定义 remove()、removeAll()、retainAll() 和 containAll()。Collection<Integer>Collection<Object>Collection<? extends E>


答案 2

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

对于删除,限制不需要如此严格地设置,并且尝试删除某些完全不相关的类型的集合的元素没有害处。例如,你可以有一个s的集合,你碰巧知道它只包含s,所以把它传递给a应该工作正常,编译器不允许这样做是愚蠢的。NumberIntegerremoveAllList<Integer>

请注意,根据 Javadoc,可以根据实现选择性地抛出一个 。removeAllClassCastException

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


推荐