为什么 Java HashSet.equals() 不检查对象是否相等?

Why does not Java HashSet.equals() check for object equality?

我今天早上遇到了这个现象,Set 中的 equals 方法不检查元素的值是否相等,而 List 会。这不符合 java 文档。

Set<MyClass> s1 = new HashSet<>();
Set<MyClass> s2 = new HashSet<>();
Set<MyClass> s3 = new HashSet<>();
Set<MyClass> s4 = new HashSet<>();
List<MyClass> l1 = new ArrayList<>();
List<MyClass> l2 = new ArrayList<>();

MyClass o1 = new MyClass();
MyClass o2 = new MyClass();

// **this gives false, and does not call MyClass.equals().**
s1.add(o1);
s2.add(o2);
boolean setCompareWithDifferentObjects = s1.equals(s2);

// this gives true, and also does not call MyClass.equals().
s3.add(o1);
s4.add(o1);
boolean setCompareWithSaveObjects = s3.equals(s4);

// this give true, and MyClass.equals() is called.
l1.add(o1);
l2.add(o2);
boolean listCompare = l1.equals(l2)

我做了一些研究。根据这个 Java doc for Set, HashSet equals , HashSet containsAll, HashSet contains,它将使用 (o==null ? e==null : o.equals(e)) 检查元素是否相等。那么为什么会这样呢?谁能给我一些提示?

谢谢!

------------这个问题的答案可以在这里找到------------

What issues should be considered when overriding equals and hashCode in Java?

我覆盖了 equals() 但没有覆盖 hashCode()...

顺便说一句,相同的集合比较在 groovy 中有效,即使没有覆盖 hashCode()。

HashSet 包括许多可以解释所有这一切的优化:首先,如果两个对象按其哈希码放入不同的桶中,或者如果它们具有完全不同的哈希码,则它们可能会跳过equals 电话。这是Object.hashCode的合约允许的;如果两个对象具有不同的哈希码,则不允许它们相互 .equals

对于另一种情况,HashSet 利用了 .equals 的约定,该约定指定如果两个对象彼此 ==,则它们必须 .equals 对彼此。 HashSet 的部分实现在这里检查元素是否为 ==,如果是,它会跳过调用 .equals.

如果每个方法都正确地实现了它的契约,这就不会改变语义; HashSet 将始终表现得就像 .equals 被调用一样。