在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