【问题标题】:equals() and hashCode() contract in JavaJava 中的 equals() 和 hashCode() 合约
【发布时间】:2011-07-09 03:44:37
【问题描述】:

Bert Bates 和 Kathy Sierra 的 SCJP 6 学习指南在第 554 页(以及其他要求)指出 x.hashCode() != y.hashCode() 要求 x.equals(y) == false 。

但是 Object 的 Javadoc 并没有明确提到这样的要求。 Quote:
如果两个对象根据equals(Object)方法相等,那么对两个对象分别调用hashCode方法必须产生相同的整数结果。

我是否应该将 Javadoc 所说的内容视为实质含义,例如 eq -> hc?那么这两个来源之间就不会有冲突了。

【问题讨论】:

    标签: java equals hashcode


    【解决方案1】:

    关于 HashMap 的基本事实。
    1. HashMap会为每个key生成hashcode,不考虑对象类型。
    2. 具体来说——根据key和value(即entry)生成hashcode

    实验: 考虑一个用户定义的对象(例如 SPObject)是 hashmap 的键; SPObject 中只有一个参数 (name)。参考:http://www.programcreek.com/2011/07/java-equals-and-hashcode-contract/

    如果在 SPObject 类中没有正确编写 hashCode() 和 equals(),问题如下。
    放置 2 个条目 - 新 SPObject("SP") 和新 SPObject("SP")。这些被视为不同的对象并成功存储在 Map 中。

    map.get(new SPObject("SP")) 将返回 null。
    map.contains(new SPObject("SP")) 将返回 false。

    如果没有正确处理 hashCode/equals 合约,这就是结果。

    hashCode() |等于() |视为 |说明
    没有 |没有 |重复 |存储在不同的桶中。
                                                 |被视为不同的对象。
    
    是 |没有 |重复 |存储在同一个桶中。
                                                 |被视为不同的对象。
                                                 |因为,default(Object) equals 方法只会检查对象的引用。
    
    没有 |是 |重复 |存储在不同的桶中。被视为不同的对象
    
    是(哈希逻辑)|是 |独特 |存储在同一个桶中。被视为同一个对象。高效。
    
    是(常数) |是 |独特 |存储在同一个桶中。被视为同一个对象。
                                                 |效率低下,因为它将迭代桶元素以进行相等性检查。
    
    

    【讨论】:

    • 解释得很好!!
    【解决方案2】:

    hashCode 背后的基本思想是,一个实体知道一个对象报告的 hashCode 值不同于其他对象有权假设对象不相等而无需进一步检查它们。因为整数支持与等价相关的各种公理,所以实体可能知道两个哈希码不同,而无需直接比较它们。例如,知道其中一个报告了偶数而另一个报告了奇数就足以表明他们无法匹配。这样的假设通常允许实体快速识别不可能包含正在查找的对象的大部分集合,因此不必费心检查这些区域。

    引用的关于 hashCode 和 equals 的两个“要求”都包含一个未说明的前提:如果X.equals(Y) 报告为真,人们不希望实体错误地认为它是假的。一般来说,代码根据错误的假设采取行动是非常糟糕的,因此不希望实体对对象的相等性做出错误假设的前提是合理的。学习指南的引用暗示了这样一个事实,即如果两个对象具有不相等的哈希码,则它们将被假定为不相等;使这种假设与现实相匹配需要它们 不平等。 JavaDoc 本质上暗示了这样一个事实,即如果两个对象相等,并且希望避免让实体假设它们不相等并且没有注意到它们相等,则必须确保一个返回的 hashCode 值也将是被对方退回。

    【讨论】:

      【解决方案3】:

      这些语句之间没有冲突,它们是等价的。

      p: x.equals(y)
      q: x.hashCode() == y.hashCode()
      p implies q
      not q implies not p
      

      【讨论】:

        【解决方案4】:

        正如 z5h 所说,这些语句是等价的。

        对于逻辑条件 x 和 y,“x 蕴含 y”与“!y 蕴含 !x”相同。

        “如果某物是公共汽车,它就是红色的”在逻辑上等价于“如果某物不是红色,它就不是公共汽车。”

        这是contraposition。

        我是否应该将 Javadoc 所说的内容视为实质含义,例如 eq -> hc。

        是的,这正是它的意思:equals 下的两个对象相等意味着它们的哈希码必须相等。

        【讨论】:

        • 感谢您的澄清!
        • “如果某物是公共汽车,它就是红色的”你真是英国人 :-)
        • Jon,你能给我举个例子,HashCode 可以相同但对象不相等吗?
        • @UnKnown:当然 - Long.valueOf(1) 和 Long.valueOf(1L << 32)。
        • @UnKnown:因为对于哈希码而言,这不是必需的。无论如何,int 的哈希冲突非常罕见。您只需要注意,散列不是唯一的,并且不应该是唯一的。
        【解决方案5】:

        这两个语句是等价的。

        简单地说:

        1. 如果两个hashcode不同,equals下的对象肯定不同。
        2. 如果两个哈希码相同,我们不知道。 (但在许多实际情况下,对象将是相等的)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-02-13
          • 2019-06-02
          • 1970-01-01
          • 1970-01-01
          • 2021-10-31
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多