Java 为什么不同类型的空集合相等?

Java 为什么不同类型的空集合相等?,java,collections,testng,Java,Collections,Testng,下面的机制是什么,使相同的类型不同 import static org.testng.Assert.assertEquals; @测试 公共无效whythisequal(){ assertEquals(新HashSet(),新ArrayList()); } 因为对于集合,只比较内容,而不比较集合类型 其背后的基本原理是,通常集合的某些子类是从测试方法返回的,与使用的子类无关。assertEquals(实际集合,预期集合)说: 断言两个集合以相同的顺序包含相同的元素。如果没有,则抛出断言错误 因

下面的机制是什么,使相同的类型不同

import static org.testng.Assert.assertEquals;
@测试
公共无效whythisequal(){
assertEquals(新HashSet(),新ArrayList());
}

因为对于集合,只比较内容,而不比较集合类型

其背后的基本原理是,通常集合的某些子类是从测试方法返回的,与使用的子类无关。

assertEquals(实际集合,预期集合)说:

断言两个集合以相同的顺序包含相同的元素。如果没有,则抛出断言错误

因此,将比较两个集合的内容,如果两个集合都为空,则它们是相等的。

它们不是

System.out.println(new HashSet<>().equals(new ArrayList<>())); // false
因此,在某个特定时间点将这些数据与
集合
进行比较将产生有趣的结果


更糟糕的是,
java-9
Set::of
方法在内部实现了随机化,因此每次运行的顺序(或不是顺序)都不同

当我在代码下运行时,条件是
false

if( (new HashSet<>()).equals(new ArrayList<>())){
            System.out.println("They are equal");
        }
if((新HashSet()).equals(新ArrayList())){
System.out.println(“它们相等”);
}

因此,对于
assertEquals
,它只检查元素及其相等顺序。但是对于
equals
,它是false

Testng调用通过这种方式实现的方法

  public static void assertEquals(Collection<?> actual, Collection<?> expected, String message) {
    if (actual == expected) {
      return;
    }

    if (actual == null || expected == null) {
      if (message != null) {
        fail(message);
      } else {
        fail("Collections not equal: expected: " + expected + " and actual: " + actual);
      }
    }

    assertEquals(
        actual.size(),
        expected.size(),
        (message == null ? "" : message + ": ") + "lists don't have the same size");

    Iterator<?> actIt = actual.iterator();
    Iterator<?> expIt = expected.iterator();
    int i = -1;
    while (actIt.hasNext() && expIt.hasNext()) {
      i++;
      Object e = expIt.next();
      Object a = actIt.next();
      String explanation = "Lists differ at element [" + i + "]: " + e + " != " + a;
      String errorMessage = message == null ? explanation : message + ": " + explanation;
      assertEqualsImpl(a, e, errorMessage);
    }
  }

我发现从junit调用
assetEquals
而不使用
Object.equals
是一个危险的选择。。。这会导致像这样的“意外”行为。@AxelH事实上,我真的没想到thisJunit会在这里抛出一个
AssertionError
。testng具有这种行为。(我看到你在我发布这条评论时正确地编辑了你的答案)@marstran看到另一个编辑,我觉得这是一个非常非常好的编辑weird@AxelH&Eugene,我同意,这个方法命名错误。这应该命名为类似assertEqualContentsOrdered的名称。在您知道集合是有序的情况下,比较列表和集合将非常有用。(已经有assertEqualsNoOrder,但它只接受数组。)它调用这个重载:@marstran-ouch,因此引用的类型而不是对象会改变行为。是的。重载应该有另一个名称imho。比如
AssertSameeElements
或其他什么东西。@marstran或assertEquals(对象,对象)应该在运行时检查,但即使这样,它也只对列表有效,而不是对列表有效Set@AxelH由于其他原因,这个函数不好,但它认为
null==null
与语言的其余部分完全一致。
if( (new HashSet<>()).equals(new ArrayList<>())){
            System.out.println("They are equal");
        }
  public static void assertEquals(Collection<?> actual, Collection<?> expected, String message) {
    if (actual == expected) {
      return;
    }

    if (actual == null || expected == null) {
      if (message != null) {
        fail(message);
      } else {
        fail("Collections not equal: expected: " + expected + " and actual: " + actual);
      }
    }

    assertEquals(
        actual.size(),
        expected.size(),
        (message == null ? "" : message + ": ") + "lists don't have the same size");

    Iterator<?> actIt = actual.iterator();
    Iterator<?> expIt = expected.iterator();
    int i = -1;
    while (actIt.hasNext() && expIt.hasNext()) {
      i++;
      Object e = expIt.next();
      Object a = actIt.next();
      String explanation = "Lists differ at element [" + i + "]: " + e + " != " + a;
      String errorMessage = message == null ? explanation : message + ": " + explanation;
      assertEqualsImpl(a, e, errorMessage);
    }
  }
Set<Integer> a = new HashSet<>();
a.add(82);
a.add(100);
System.err.println(a);
Set<Integer> b = new HashSet<>();
for (int i = 82; i <= 100; i++)
    b.add(i);
for (int i = 83; i <= 99; i++)
    b.remove(i);
System.err.println(b);
System.err.println("a.equals(b) && b.equals(a) is " + (a.equals(b) && b.equals(a)));
assertEquals(a, b, "a <=> b");
Set<Integer> a = new HashSet<>();
a.add(100);
a.add(82);
System.err.println(a);
Set<Integer> b = new HashSet<>(32);
b.add(100);
b.add(82);
System.err.println(b);
System.err.println("a.equals(b) && b.equals(a) is " + (a.equals(b) && b.equals(a)));
assertEquals(a, b, "a <=> b");
[82, 100]
[100, 82]
a.equals(b) && b.equals(a) is true
Exception in thread "main" java.lang.AssertionError: a <=> b: Lists differ at element [0]: 100 != 82
    at ....
assertEquals(a, (Iterable) b); // passes

assertEquals(a, (Object) b); // passes

assertEquals(Arrays.asList(a), Arrays.asList(b)); // passes