这是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
<?>
有{{1}}
答案 0 :(得分: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 }
但实际上是这样的:
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);
如果上述片段以明显的方式进行了生成(使用ca
Collection<Integer>
和raCollection<Object>
),那么如果removeAll()的签名要求其参数为a,则上述代码将无法编译Collection<? extends E>
,而不是无操作。生成类库的一个关键目标是不破坏或更改现有代码的语义,因此必须使用比它们更弱的类型约束定义remove(),removeAll(),retainAll()和containsAll()他们可能已经从头开始重新设计了仿制药。
答案 1 :(得分:7)
对于包含E
类型元素的任何集合,addAll
必须能够处理不仅E
的输入集合,而且还需要处理所有子类的输入集合。因此<? extends E>
。如果没有这个,您就无法将List<Integer>
的所有元素添加到List<Number>
,这显然不对。*
对于删除,限制不需要如此严格设置,并且尝试删除某些完全不相关类型的集合的元素没有任何害处。例如。您可以拥有一个Number
的集合,您恰好知道它只包含Integer
个,因此将其传递给removeAll
上的List<Integer>
应该可以正常工作,如果编译器不允许这样做,那将是愚蠢的。
请注意,according to the Javadoc,removeAll
可以选择抛出ClassCastException
,具体取决于实施方式。
*背后的原因是在Java中,泛型是不变的。有关详情,请参阅例如this thread
答案 2 :(得分:3)
<?>
的限制性低于<? extends E>
。
从苹果系列中去除橙子没有任何问题; 将橙色添加到苹果集合中会出现很多问题。
答案 3 :(得分:2)
当您向集合中添加项目时,您希望确保它们具有某种类型。
删除它们时,只会删除集合中的那些。无论他们的类型如何。
答案 4 :(得分:0)
Java通过擦除实现泛型。这些信息仅适用于编译时间。我想java集合设计师这样做是为了保留与pre-generics java版本更好的兼容性。
答案 5 :(得分:0)
当你添加一个对象时,它需要是主类型的子类(或子子类等)。删除对象时,它会将其作为集合的类型返回。这是polymorphism实施的一个很好的例子。
答案 6 :(得分: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);
}
}
答案 7 :(得分: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
}
}
答案 8 :(得分:0)
不需要删除限制,因此只需<?>
,但在添加时我们必须检查然后添加类型安全,因此addAll具有限制<? extends E>
答案 9 :(得分: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