通用集合

时间:2012-03-06 14:12:24

标签: 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);
    /* ... */   
}

为什么addAll <? extends E> removeAll <?>有{{1}}

10 个答案:

答案 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>和ra Collection<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 JavadocremoveAll可以选择抛出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