【问题标题】:Why does not Java HashSet.equals() check for object equality?为什么 Java HashSet.equals() 不检查对象相等性?
【发布时间】:2016-01-06 00:04:35
【问题描述】:

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

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 SetHashSet equalsHashSet containsAllHashSet contains,它将使用 (o==null ? e==null : o.equals(e)) 来检查元素是否相等。那么为什么会这样呢?谁能给我一些提示?

谢谢!

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

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

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

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

【问题讨论】:

  • 你是否正确实现了equals和hashcode方法?
  • 我实现了 MyClass.equals() 但没有实现 hashCode()。但是在第一次比较中,MyClass.equals 根本没有输入,即使 == 失败。
  • 叹息......如果你还没有实现hashCode(),这解释了你所看到的一切。 equals()hashCode() 必须彼此一致。另外,请不要在 SO 输入文本框中重新输入代码。始终复制/粘贴,以免引入转录错误 (l2.add(l2))。一个这样明显的错误会使您的整个代码示例受到怀疑,并导致不必要的澄清请求。

标签: java list set equals hashset


【解决方案1】:

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

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

如果每个方法都正确地实现了它的契约,这不会改变语义; HashSet 的行为总是与调用 .equals 完全相同。

【讨论】:

  • 这在python中也是一样的。不过我一直在寻找证据。可以链接吗?
  • HashSet的源码,其实是HashMapHereHashMap.containsKey 的来源,如上所述,它只在同一个桶中查找,验证哈希是否完全相等,然后在调用equals 之前测试对象是否为==
  • 真正的问题是第一次检查,即使两个对象通过equals()方法相等,它也会给出假。这意味着 == 给出 false 并且 HashSet 不调用 equals。这是我认为不符合合同的。
  • @xing,那么你的对象违反了他们自己对hashCode() 的合同。如果您的哈希码无效,HashSet 将无法工作。任何两个.equals 的对象必须具有相同的hashCode()
  • 我很好奇投反对票的原因。我已经说过,根据Object 合约,如果两个对象具有不同的哈希码,则不允许它们是.equals
猜你喜欢
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-26
  • 2015-07-19
  • 1970-01-01
相关资源
最近更新 更多