6

为什么 boolean containsAll(Collection < ?> c); 每种类型都允许收集框架的方法吗?.但是 boolean addAll(Collection< ?extends E> c); 允许?扩展 E。所以,我写了一个程序来澄清。这是我的程序

public class ContainAllTest {
    // take ServiceDto 
    ArrayList<ServiceDto> resultList = new ArrayList<ServiceDto>();

    void Test() {

        ServiceDto serviceDto = new ServiceDto();
        serviceDto.setName("test");
        resultList.add(serviceDto);
        // another arraylist that takes String 
        ArrayList<String> resultList1 = new ArrayList<String>();
        resultList1.add("test");
        // no error, goes for run time.Contain all checking is done for two generic type ServiceDto and String:
        resultList.containsAll(resultList1);
        // error shown at compile time,as addAll take ServiceDto as generic type but the generic type for resultList1 take String:
        resultList.addAll(resultList1);    
    }

所以,我的问题是我什么时候可以利用 resultList.containsAll(resultList1); 当泛型类型不同时。在我的情况下是 String 和 ServiceDto 。用boolean containsAll(Collection< ?extends E> c)替换boolean containsAll(Collection< ? > c)是否有问题

4

3 回答 3

3

我猜原因是containsAll(and contains, remove, removeAll)Object#equals用于比较。

可以想象,您可以拥有一个覆盖Object#equals方法,E该方法可以返回true某些不相关类的对象。并不是说这是一个好主意,但它可能是一个有效的实现。

于 2013-08-15T07:56:10.313 回答
2

这并不是为了节省 cpu 滴答声。泛型被编译器擦除并替换为强制转换。

对于addAll方法类型的安全性需要考虑。应该只允许用户向 a 添加一个或Collection<E>某个子类。ECollection<E>

如果您查看源代码,AbstractCollection您会看到此方法:

public boolean addAll(Collection<? extends E> c) {
    boolean modified = false;
    for (E e : c)
        if (add(e))
            modified = true;
    return modified;
}

编译后它看起来(某些东西)像

public boolean addAll(Collection c) {
    boolean modified = false;
    for (Object e : c)
        if (add((E)e))
            modified = true;
    return modified;
}

即要添加的集合的每个元素都需要在添加之前从Objectto 转换为。E

对于containsAll方法来说没关系。由于该equals方法已定义为equals(Object other)您可以安全地与任何其他方法一起调用它,Collection并且没有ClassCastExceptions 的风险。通过避免使用泛型,编译器可以避免添加强制转换。

于 2013-08-15T07:13:26.563 回答
1

原因与方法add和相同contains

add接受集合的泛型类型的参数,因为只有这样的对象才能添加到集合中。这就是在集合中使用泛型的全部意义所在。

contains(以及集合框架中的其他方法,如removeand Map.get)接受任何对象作为参数。至少有两个原因。

首先,正如 Tobias Brandt 所说,可能存在与集合中的对象“相等”(由其equals实现定义)的完全独立类型的对象。

其次,每个集合Collection<E>都可以看作是Collection<? extends D>D 是 E 的超类,甚至可以看作Collection<?>(与 相同Collection<? extends Object>)。如果您执行此向上转换,则无法再调用该add方法,因为它的签名看起来像add(?)并且编译器禁止调用它,因为它永远无法确保类型安全(而且您不能调用它很好,add因为您可能会添加错误的类型到集合)。但是,调用它可能仍然有用,contains而且这始终是类型安全的,那么为什么不允许它呢?为了允许这一点,该contains方法需要具有Object作为参数类型,否则它不能被称为类似于add.

addAll和的签名containsAll遵循同样的原则。

于 2013-08-15T11:37:43.610 回答