在Java中,相同类型但不同类型参数的空集合是否总是相等的?
考虑以下代码段:在Java中,相同类型但不同类型参数的空集合是否总是相等的?,java,generics,equals,Java,Generics,Equals,考虑以下代码段: List<String> list1 = new ArrayList<>(); List<Integer> list2 = new ArrayList<>(); assertThat(list1.equals(list2), is(true)); 但也许你可以做类似的事情this.type=T。(这不会编译,但可能会有类似的功能。)这实际上取决于实现集合接口的各个子类如何处理equals()方法。对于Ar
List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
assertThat(list1.equals(list2), is(true));
但也许你可以做类似的事情
this.type=T
。(这不会编译,但可能会有类似的功能。)这实际上取决于实现集合接口的各个子类如何处理equals()方法。对于ArrayList,实现在AbstractList中,如下所示:
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof List))
return false;
ListIterator<E> e1 = listIterator();
ListIterator<?> e2 = ((List<?>) o).listIterator();
while (e1.hasNext() && e2.hasNext()) {
E o1 = e1.next();
Object o2 = e2.next();
if (!(o1==null ? o2==null : o1.equals(o2)))
return false;
}
return !(e1.hasNext() || e2.hasNext());
}
公共布尔等于(对象o){
如果(o==这个)
返回true;
如果(!(列表实例))
返回false;
ListIterator e1=ListIterator();
ListIterator e2=((List)o).ListIterator();
而(e1.hasNext()&&e2.hasNext()){
eo1=e1.next();
对象o2=e2.next();
如果(!(o1==null?o2==null:o1.equals(o2)))
返回false;
}
返回!(e1.hasNext()| e2.hasNext());
}
因此,如果相反的对象也是一个列表,并且大小相同,并且每个元素都相等,则返回true。因此,如果两个列表都为空,则结果必须为真。如您所述,在给定示例中,类型信息在运行时丢失。但是关于你在评论中提出的问题: 您是否还可以显示一个反例,即一个集合,其中不同泛型类型的两个空实例不会被视为相等 当然,您可以实现自己的
集合
,该集合不考虑equals
方法中的类型信息。下面是一个非常简单的示例,它围绕任意的列表创建类型列表
包装器:
static final class TypedList<T> extends AbstractList<T> {
private final List<T> delegate;
private final Class<T> type;
public TypedList(List<T> delegate, Class<T> type) {
this.delegate = Objects.requireNonNull(delegate);
this.type = Objects.requireNonNull(type);
}
@Override
public T get(int index) {
return delegate.get(index);
}
@Override
public int size() {
return delegate.size();
}
@Override
public boolean equals(Object obj) {
if (!super.equals(obj)) {
return false;
}
// Lists are equal, now additionally, check the type
TypedList<?> other = (TypedList<?>) obj;
return this.type.equals(other.type);
}
// hashCode omitted for brevity
}
静态最终类TypedList扩展了AbstractList{
非公开最终名单代表;
私有最终类类型;
公共类型列表(列表委托,类类型){
this.delegate=Objects.requirennull(委托);
this.type=Objects.requirennull(类型);
}
@凌驾
公共T获取(整数索引){
返回delegate.get(索引);
}
@凌驾
公共整数大小(){
返回delegate.size();
}
@凌驾
公共布尔等于(对象obj){
如果(!super.equals(obj)){
返回false;
}
//列表是相等的,另外,请检查类型
TypedList other=(TypedList)obj;
返回this.type.equals(other.type);
}
//为了简洁起见,省略了hashCode
}
注意,由于前面提到的类型擦除,您需要显式存储该类型。用法:
List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list1.equals(list2)); // true
list1 = new TypedList<>(list1, String.class);
list2 = new TypedList<>(list2, Integer.class);
System.out.println(list1.equals(list2)); // false
List list1=new ArrayList();
List list2=新的ArrayList();
System.out.println(list1.equals(list2));//符合事实的
list1=新的类型列表(list1,String.class);
list2=新的类型列表(list2,Integer.class);
System.out.println(list1.equals(list2));//错误的
泛型用于编译时的类型检查
如果像这样创建ArrayList
:
List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list1.equals(list2)); // result:true
这将返回false
,因为ArrayList
条目是不同的“这实际上取决于实现集合接口的各个子类如何处理equals()方法。”,是否真的有可能以不同的方式处理equals
,而不是ArrayList
如何处理。换句话说:你能不能也展示一个反例,即一个集合,其中两个不同泛型类型的空实例不会被视为相等?+1,这是我没有想到的方式。现在,下一个问题是,这可以实现这一点,而无需显式地将类型作为参数传递(如果您以某种方式从委托
中提取它,我很好。但我尝试了,但失败了)。我将使用此新的详细信息编辑问题。简短否定回答:没有显式类型标记,这是不可能的。列表
在运行时实际上只是一个列表
,因此信息就不存在了。对于Class
中的类型,它是不同的,因为这是一个“一等公民”--即使在运行时它只是Class
,它仍然会保存提供的类型信息(例如String.Class
,…)侧注:java.util.Collections
遵循完全相同的原则,例如,在此方法中:java.util.Collections.checkedList(List,Class)
——类型参数需要作为参数显式传递。但请注意,checkedList
不会处理空列表的特定情况。这只是API设计的一个例子!阿吉特:我基本上理解它是如何工作的,以及为什么在我的例子中,它会返回真值。但我不同意这种说法“列表1和列表2将是相等的,因为它们是空的”。对我来说,这两个列表在概念上不可能相等,因为它们属于不同的类型。我宁愿看到这样一个事实,即这不能作为Java的一个短期特性(或至少是特性)来检查,我很好奇是否有办法解决这个问题。
List<String> list1 = new ArrayList<>();
List<Integer> list2 = new ArrayList<>();
System.out.println(list1.equals(list2)); // result:true
List<String> list1 = new ArrayList<>();
list1.add("A");
List<Integer> list2 = new ArrayList<>();
list2.add(1);
System.out.println(list1.equals(list2)); // result: false