Java 布尔containsAll(Collection<;?>;c)与布尔addAll(Collection<;?extends E>;c)的设计决策;在集合框架中

Java 布尔containsAll(Collection<;?>;c)与布尔addAll(Collection<;?extends E>;c)的设计决策;在集合框架中,java,generics,wildcard,Java,Generics,Wildcard,为什么布尔包含所有(集合c);每种类型都允许使用收集框架方法?。但是布尔addAll(收集c) 是否允许?扩展E。因此,我编写了一个程序进行澄清。 这是我的节目 public class ContainAllTest { // take ServiceDto ArrayList<ServiceDto> resultList = new ArrayList<ServiceDto>(); void Test() { Service

为什么布尔包含所有(集合<?>c);每种类型都允许使用收集框架方法。但是布尔addAll(收集<?扩展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);    
    }
公共类ContainAllTest{
//接受服务
ArrayList resultList=新建ArrayList();
无效测试(){
ServiceDto ServiceDto=新ServiceDto();
服务到setName(“测试”);
结果列表.add(serviceDto);
//另一个接受字符串的arraylist
ArrayList resultList1=新的ArrayList();
结果列表1.添加(“测试”);
//无错误,适用于运行时。包含对两个通用类型ServiceDto和String的所有检查:
resultList.containsAll(resultList1);
//编译时显示的错误为addAll take ServiceDto作为泛型类型,但resultList1的泛型类型为take字符串:
resultList.addAll(resultList1);
}

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

这并不是为了节省cpu时间。泛型由编译器提供,并由强制转换代替

对于
addAll
方法,需要考虑类型安全。只允许用户将
集合
E
的某些子类添加到
集合

如果查看
AbstractCollection
的源代码,您会看到以下方法:

public boolean addAll(Collection<? extends E> c) {
    boolean modified = false;
    for (E e : c)
        if (add(e))
            modified = true;
    return modified;
}
即,要添加的集合的每个元素在添加之前都需要从
对象
转换为
e


对于
containsAll
方法,这无关紧要。因为
equals
方法被定义为
equals(对象其他)
您可以安全地将其与任何其他
集合一起调用,并且没有发生
类异常的风险。通过避免使用泛型,编译器可以避免添加类型转换。

我猜原因是
包含所有
(并且
包含
删除
删除所有
)使用
Object#equals
进行比较


可以想象,您可以在
E
中有一个重写的
Object#equals
方法,该方法可以为一些不相关类的对象返回
true
。这不是一个好主意,但可能是一个有效的实现。

原因与方法
add
contains
相同

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

包含
(以及集合框架中的其他方法,如
删除
映射。获取
)接受任何对象作为参数。至少有两个原因

首先,正如Tobias Brandt所说,可能有完全不同类型的对象与集合中的对象“相等”(由它们的
equals
实现定义)


其次,每个集合
collection
都可以被视为
collection
(这与
CollectionEquals和hashCode是Object中的方法相同,也就是说,当您搜索包含某些内容的集合时,您不需要每次都将其转换为适当的类型。@artbristol:是的,这基本上是同一个问题,并且有更好的答案。我将投票将其标记为重复。这将是正确的如果我不得不将我收藏的内容复制到一个收藏中,那就太乏味了。我认为这与“cpu滴答声”无关@assylias Casting不是免费的。但它也有提供更好的接口规范的优势。Casting可能不是免费的,但我认为它与类的设计无关。它是一条指令(
checkcast
)。我不认为这有什么关系。更重要的是:对ˋEˋ的强制转换是一种未经检查的强制转换,只在运行时检查ˋObjectˋ。因此,在这种情况下它是不可操作的,并且是免费的!因此,这当然不是设计决策背后的原因。我怀疑原因与向后兼容性有关。这有时是个好主意。例如,
java.util.List
要求
.equals()
对于具有相同内容的列表,甚至对于不同的列表类,返回true。“但是,调用contains可能仍然有用,并且这始终是类型安全的”,但这也是因为
对象.equals()
接受所有类型。如果
对象.equals()
没有接受所有类型,那么它就不总是类型安全的。
public boolean addAll(Collection c) {
    boolean modified = false;
    for (Object e : c)
        if (add((E)e))
            modified = true;
    return modified;
}