Java 布尔containsAll(Collection<;?>;c)与布尔addAll(Collection<;?extends E>;c)的设计决策;在集合框架中
为什么布尔包含所有(集合<?>c);每种类型都允许使用收集框架方法?。但是布尔addAll(收集<?扩展E>c)强> 是否允许?扩展E。因此,我编写了一个程序进行澄清。 这是我的节目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
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;
}