【问题标题】:Why does Java need equals() if there is hashCode()?如果有 hashCode(),为什么 Java 还需要 equals()?
【发布时间】:2017-03-16 11:32:29
【问题描述】:

如果两个对象返回相同的hashCode,是不是意味着它们相等?或者我们需要equals来防止碰撞?

我可以通过比较 hashCodes 来实现 equals 吗?

【问题讨论】:

标签: java object


【解决方案1】:

如果有 hashCode(),为什么 Java 还需要 equals()?

Java 需要equals(),因为它是通过检查类、字段和设计人员认为是相等性测试的一部分的其他条件来测试对象相等性的方法。

hashCode() 的目的是提供一个主要供散列表使用的散列值;虽然它也可以用于其他目的。返回的值基于对象的字段和其复合和/或聚合对象的哈希码。该方法不考虑对象的类或类型。

equals()hashCode() 之间的关系是一种暗示。

  • 两个相等的对象意味着它们具有相同的哈希码。
  • 具有相同哈希码的两个对象并不暗示它们相等。

后者不成立有几个原因:

  • 两个不同的对象有可能返回相同的哈希码。请记住,哈希值会将大量数据中的信息折叠成较小的数字。
  • 具有相似字段的不同类的两个对象很可能使用相同类型的哈希函数,并返回相等的哈希值;然而,它们并不相同。
  • hashCode() 可以是特定于实现的,在不同的 JVM 或 JVM 目标安装上返回不同的值。

在同一个 JVM 中,hashCode() 可以用作相等的廉价前体,方法是首先测试已知的哈希码,并且只有在相同的测试实际相等的情况下;前提是相等性测试比生成哈希码要昂贵得多。

我可以通过比较 hashCodes 来实现 equals 吗?

没有。如前所述,相等的哈希码并不意味着相等的对象。

【讨论】:

    【解决方案2】:

    如果两个对象具有相同的 hashCode,则它们不一定相等。否则你会发现完美的散列函数。但反之亦然——如果对象相等,那么它们必须具有相同的 hashCode。

    【讨论】:

    • 示例:"FB".hashCode() == "Ea".hashCode().
    • 这也意味着:如果两个对象没有相同的 hashCode 则它们不相等。
    【解决方案3】:

    hashCodeEquals 是关于对象的不同信息

    考虑类比人,其中哈希码是生日,

    在那种情况下,你和许多其他人有相同的生日(相同的哈希码),但是你们不是同一个人..

    【讨论】:

      【解决方案4】:

      有时(很多时候?)你不知道!

      这些答案并非不真实。但他们并没有讲述整个故事。

      一个示例是,您正在创建一组 SomeClass 类的对象,并且通过在构造函数中增加静态变量 nInstanceCount 或类似变量,为创建的每个实例分配一个唯一 ID:

      iD = nInstanceCount++;
      

      你的哈希函数可能然后是

      int hashCode(){
          return iD;
      }
      

      然后你的等号可能

      boolean equals( Object obj ){
          if( ! ( obj instanceof SomeClass )){
              return false;
          }
          return hashCode() == obj.hashCode();
      }
      

      ...在这种情况下,您认为“等于是多余的”的想法实际上是正确的:如果所有类的行为都是这样,Java 10(或 Java 23)可能会说,啊,让我们摆脱愚蠢的老 equals , 重点是什么? (NB 向后兼容性将会消失)。

      有两个要点:

      • 然后您不能创建多个 MAXINTSomeClass 实例。或者...您可以 ...如果您设置了一个系统来重新分配以前销毁的实例的 ID。 ID 通常是long 而不是int ...但这不起作用,因为hashCode() 返回int

      • 这些对象中的任何一个都不能与另一个对象“相等”,因为您已经定义了这个特定类的 equality = identity。这通常是可取的。通常它会关闭所有可能的途径......

      您的问题的必要含义也许是,这两种方法有什么用,以一种相当烦人的方式,必须“合作”? Frelling 在他/她的回答中提到了关键点:需要散列码来分类到像 HashMap 这样的类的“桶”中。值得一读:为HashMap 之类的类设计高效的“桶”机制所涉及的高级数学数量非常可怕。读完之后,您可能会(和我一样)对如何以及为什么要费心实施hashCode() 稍加思考,产生一点理解和敬意!

      【讨论】:

        【解决方案5】:

        Oracle 文档中所述的hashCode 方法是Java 中对象的数字表示。此哈希码的可能值有限(由可以存储在 int 中的值表示)。

        对于更复杂的类,您很有可能会找到两个具有相同哈希码值的不同对象。此外,没有人阻止您在任何课程中这样做。

        class Test {
        
            @Override
            public int hashCode() {
                return 0;
            }
        
        }
        

        所以,不建议通过比较哈希码来实现equals方法。仅当您可以保证每个对象都有唯一的哈希码时,才应使用它们进行比较。在大多数情况下,您唯一可以确定的是,如果两个对象使用 o1.equals(o2) 相等,则 o1.hashCode() == o2.hashCode()

        equals 方法中,您可以定义更复杂的逻辑来比较同一类的两个对象。

        【讨论】:

        • 我认为这对于更好地理解 hashCode()-equals()-relation 非常有帮助,以了解始终返回 0 的 hashCode() 实现在其一般合同方面是完全有效的。不幸的是,所有有用的信息都分布在不同的答案中。
        • 是的,这里的答案有很多有用的信息,但是很难将关于 hashCode() 和 equals() 的所有内容浓缩在一个答案中:D。
        【解决方案6】:

        如果两个对象返回相同的hashCode,是不是等于它们相等?

        不,不是那个意思。

        Objectjavadocs 声明如下:

        hashCode的总合约是:

        • 在 Java 应用程序执行期间,在同一对象上多次调用时,hashCode 方法必须始终如一 返回相同的整数,但未提供equals 中使用的信息 对象上的比较被修改。 ...
        • 如果两个对象根据equals(Object)方法相等,那么必须对这两个对象中的每一个调用hashCode方法 产生相同的整数结果。
        • 如果两个对象根据equals(java.lang.Object)方法不相等,则不要求调用hashCode方法 这两个对象中的每一个都必须产生不同的整数结果。 ...

        注意突出显示的语句。它清楚地对您的问题说“不”。


        还有另一种看法。

        1. hashCode 返回一个int
        2. int 只能采用 232 个不同的值。
        3. 如果 a.hashCode() == b.hashCode() 隐含 a.equals(b),那么在运行的 Java 应用程序中的任何给定时间都只能有 232 个不同(即互不相等)的对象。

        最后一点显然不正确。事实上,如果您有足够大的堆来在 64 位 JVM 中容纳 232java.lang.Object ... 的实例,这显然是不正确的。


        第三种方法是一些众所周知的例子,其中两个不同的两个字符串具有相同的哈希码。


        鉴于您的假设不正确,由此得出的推理也是不正确的。

        1. Java 确实需要equals 方法。
        2. 您通常无法仅使用 hashCode 来实现 equals

        您可以使用hashCode 实现更快的equals 方法,但前提是调用hashCode 两次比比较两个对象更快。一般不会。

        【讨论】:

          【解决方案7】:

          hashCodes 相等 -> 对象可能相等 -> 需要进一步比较
          hashCodes 不同 -> 对象不相等(如果 hashCode 实现正确)

          这就是equals方法的实现方式。首先,您检查 hashCodes 是否相等。如果是,您需要检查类字段以查看它是否代表完全相同的对象。如果 hashCode 不同,可以确定对象不相等。

          【讨论】:

            猜你喜欢
            • 2019-01-22
            • 2012-02-23
            相关资源
            最近更新 更多