【问题标题】:hashcode and equals contract vice versahashcode 和 equals 合约反之亦然
【发布时间】:2012-11-26 17:48:00
【问题描述】:

我知道合同说“如果两个对象相等,那么它们应该返回相同的哈希码”。那是为了让那些对象可以被放置在同一个哈希桶中并且改进哈希码相关的收集函数知道。再说一遍为什么它说“如果两个对象具有相同的哈希码,那么它们不应该总是相等”。我的意思是,如果在合同中是真的,我们应该说“如果两个对象相等,它们可能会返回相同的哈希码,但这不是强制性的”

【问题讨论】:

  • 两个相同的苹果价格应该相同,即 1 个金币。但是,两个价值 1 个金币的物品不必是相同的苹果。

标签: java equals hashcode


【解决方案1】:

我的意思是,如果在合同中是真的,我们应该说“如果两个对象相等,它们可能返回相同 哈希码,但不是强制性的”

不,不应该。这是因为,每当搜索一个对象时,比如说在 HashMapHashSet 中,然后首先根据 hashCode 搜索它(注意:- hashCode() 不是用于ArrayListLinkedList情况下的搜索。它们不是hash based集合),然后如果两个对象具有相同的hashcode,则移动到equals方法来比较对象本身。

现在假设如果上述陈述为真,那么对于这些​​对象,第一个测试本身将失败。也就是说,如果允许两个相等的对象有不同的hashcode,那么在搜索特定的hashCode时,它不会返回正确的结果,因此测试不会进行到equals method,并将这些对象声明为@ 987654331@,即使您希望它们是平等的。

现在让我们转到第二个语句:-

如果两个对象具有相同的哈希码,则它们不应该总是相等”

让我们这样理解: - 由于为每个对象生成的@​​987654332@ 的类型为int,因此您可以生成最大的2 ^ 32 唯一hashcodes。所以,想象一下如果你想存储更多的对象会发生什么。在这种情况下,two different objects 必须有一个 collison。因此,除了将相同的 hashCodes 分配给两个不同的对象外,您别无他法。因此,上述说法是有道理的。


所以,两件事从上面的解释中很清楚:-

  • 两个相同的对象必须具有相同的 hashCode。
  • 两个不同的对象可以有相同的 hashCodes。

以下链接中有关此主题的更多详细信息(没有比这更好的解释了):-

【讨论】:

  • 我已经编写了一个示例程序来测试您提到的内容。我只覆盖了 A 的 equals 方法,但没有覆盖哈希码。但下面返回true。你能解释一下为什么输出 true 重新运行,因为我从来没有为列表添加 a3 并且正如你提到的这些对象有不同的哈希码,并且由于在列表中找不到 a3 哈希码,它应该返回 false 对吗? A a1 = 新 A(); a1.setName("a"); A a2 = 新 A(); a2.setName("a"); A a3 = 新 A(); a3.setName("a");列表列表 = 新的 ArrayList(); list.add(a1);列表.add(a2); System.out.println(list.contains(a3));
  • @HarshanaD.. 抱歉没有提及,hashCodes 不用于搜索Lists。它用于地图 - HashMapLinkedHashMapHashtableHashSet。这就是它起作用的原因。我已经相应地编辑了我的答案。 - 我的第一部分答案。
  • @HarshanaD.. 尝试使用相同的代码,但使用Set<A> set = new HashSet<A>();,而不是ArrayList。你不会得到真正的价值。
  • 是的,在这种情况下它返回 false。所以它就像集合集将检查 a3 的哈希码是否位于该集合中知道。由于这 3 个对象具有不同的哈希码,因此即使对象状态相等,它也会返回 false。因此,如果我们为这些对象设置相同的哈希码,则集合将直接进入 a3 哈希码桶并检查我们是否拥有该对象是否正确?这是在集合中查找元素的算法。首先去那个哈希码桶,如果没有找到,迭代集合中的每个元素并检查哈希码匹配?
  • 因此,一旦我们覆盖了哈希码,即使从技术上讲该对象不在该集合中,它也会为包含返回 true。但是根据equals的约定,这种行为是正确的,因为包含需要检查对象状态的相似性而不是对象是否在物理上不同的东西知道吗?
【解决方案2】:

不。文档是正确的,而您却搞混了。

  • 两个相等的对象必须具有相同的哈希码。
  • 两个 具有相同哈希码的对象可能不相等。
  • 为了 哈希表的性能,你通常需要两个不是的对象 等于尽可能多地使用不同的哈希码。

例如,以下始终是hashCode() 的有效实现:

public int hashCode() { 
  return 0;
  // clearly all equal objects have the same hash code -- 0
  // but it's totally okay that unequal objects also have the same hash code
}

【讨论】:

    【解决方案3】:

    HashMap 可以在每个存储桶中存储多个 条目,选择哪个存储桶取决于哈希码。 HashMap 通过使用hashcode() 识别存储桶,然后equals() 在该存储桶中查找匹配的键来查找键的条目。

    鉴于上述情况,您应该清楚地看到重复的哈希码几乎没有问题(如果多个对象具有相同的哈希码但一切仍然有效,则会影响 HashMaps 的性能

    【讨论】:

      【解决方案4】:

      如果 2 个相同的哈希码必须来自同一个对象,那么哈希就不会那么安全了。从技术上讲,可以根据哈希计算出密码是什么。这会破坏哈希码的目的(至少在安全意义上)。

      对于非安全散列,如果您可以让每个唯一值生成唯一散列,那么您将解决未解决的计算问题。

      【讨论】:

        【解决方案5】:

        散列函数通常是

        单向函数

        :某些输入值(对象)可能会产生相同的哈希码。

        【讨论】:

          猜你喜欢
          • 2011-07-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-15
          • 2012-12-10
          相关资源
          最近更新 更多