【问题标题】:Java hashCode() method override is not needed if we don't use hashmap or hashset如果我们不使用 hashmap 或 hashset,则不需要 Java hashCode() 方法覆盖
【发布时间】:2013-01-24 17:03:33
【问题描述】:

我的同事重写了equals() 方法。我的回答是,你是否也覆盖了hashCode() 方法?他的回答是因为我们不会使用散列映射或散列集,如果我们覆盖hashCode() 并不重要。对吗?

【问题讨论】:

    标签: java equals hashcode


    【解决方案1】:

    是的,事实上他是对的——但是,如果有一天你需要将你的对象放在一个基于哈希的集合中,你将不得不在任何地方添加哈希码,这可能会很烦人 + 那天你可能会错误地实现你的哈希码(即与equals不一致)因为你错过了equals方法中的一些微妙之处......

    考虑到大多数 IDE 都提供自动 equals/hashcode 生成功能,我认为没有理由不同时创建两者。

    另一种看待它的方式是:当您从父类重写方法时,您应该遵循该父类定义的协定。在 Object 的情况下,javadoc of equals 非常清楚:

    请注意,通常需要在任何时候重写 hashCode 方法,以维护 hashCode 方法的一般约定,即相等的对象必须具有相等的哈希码。

    因此,除非您有真正的设计理由不覆盖哈希码,否则默认决定应该是遵循父类契约并且不覆盖或覆盖两者

    【讨论】:

    • +1 但是另一方面,如果 equals 是代码现在所依赖的,那么 hashCode 很有可能落后于 equals 的更改,再次结束与它不一致。在我看来,最好的折衷方案是简单的return 1;——至少它在技术上是正确的。
    • 我对@9​​87654326@ 的问题是,如果您稍后使用HashSet,它似乎可能会导致静默、难以调试的性能问题。相反,我将hashCode() 实现为throw new UnsupportedOperationException(),这需要最少的努力,但是当您稍后返回并使用HashSet 时,很明显您没有费心第一次实现hashCode()。跨度>
    • @LouisWasserman 如果您真的不想实现哈希码,则抛出异常确实是一个非常好的主意。
    • 非常感谢大家! assylias - 在第一段中“你必须在任何地方添加哈希码”是什么意思?难道我的同事只需要将hashCode() 方法添加回他覆盖equals() 的那个类吗?
    • 如果只涉及一个类,那么是的,您只有一种方法可以添加 - 我以为他想将它应用于许多类。
    【解决方案2】:

    如果您覆盖equals(),请同时覆盖hashCode()。即使您现在不使用hashCode(),您或其他人也可能会使用它。

    有关此主题的更多信息,请查看优秀的SO answer

    【讨论】:

      【解决方案3】:

      这是一种代码味道。例如,如果您覆盖 hashCode 或 equals 而不覆盖另一个,Findbugs 会警告您。您应该覆盖两者,以使它们彼此一致(即 a.equals(b) => a.hashCode() == b.hashCode())。

      现在稍加努力,以后可能会省去很多麻烦。

      【讨论】:

      • 或者.. 在一个并非设计为键的类(例如可变)上使用 hashCode 可能会在以后给您带来更多麻烦。没有覆盖的 hashCode 会立即被捕获,破坏的 hashCode 更难追踪。
      • 如果它不应该是哈希结构中的键,您可以在哈希码中抛出异常......当协议消息包含 MessageSet 时,例如在 Google 协议缓冲区中就有这样的先例跨度>
      • 如果有能力破坏现有代码,这是一个很好的解决方案(总体而言,没有人期望hashCode() 抛出异常)。我知道使用 hashCode 来测试 null 的代码(即期待 NPE)[伪造的 getClass() 会更好] - 所以再次可能没问题 - 但提出默认设置有点冒险。
      【解决方案4】:

      您必须在每个覆盖 equals 的类中覆盖 hashCode。否则将导致违反 Object.hashCode 的一般约定,这将阻止您的类与所有基于哈希的集合(包括 HashMap、HashSet 和 Hashtable)一起正常运行。

      Effective Java Item 9:当你覆盖 equals 时,总是覆盖 hashCode。

      如果您的课程是公共课程,那么您无法控制您的课程在未来开发中的使用方式。如果不查看源代码(或通过反射),就无法知道这个类是否覆盖了 hasCode 方法,如果用户在任何基于散列的集合中使用它,用户会对结果感到惊讶。

      【讨论】:

      • 这是真的!我认为我的同事可能没有考虑将他的代码发布给其他人使用,并且他可能会成为框架的主要工作人员。
      【解决方案5】:

      实际上假设您创建了两个不同的对象,而没有覆盖 equals 和 hashCode 方法。然后如果你调用 equals 方法 java 隐式调用 hashCode 方法然后检查 hashcode 的相等性。

      重写 hashCode 方法足以检查两个对象的相等性。它对未来很有用。你可以在集合上使用这个类。

      否则如果你只实现equal方法,它只会解决两个对象的相等问题。

      【讨论】:

      • Java 不会隐式调用hashCode 来实现equals 的默认实现。它使用== 验证两个对象指向同一个引用。你可以让hashCode 在每次调用时返回一个随机值,如果你指向同一个对象,equals 的默认实现仍然有效。
      • 您关于通过 hashCode() 检查相等性的说法实际上是不正确的。相同的哈希码并不能保证你是平等的。
      • 是的,标记你是对的,它检查参考。 ATrubka,在我的回答中,我特别指定了 Object 类的默认实现将用于我的示例。我的答案中未指定的其他可能性。
      【解决方案6】:

      一般:

      只覆盖那些您想以自己的方式使用的方法,以及那些受此覆盖影响的方法。

      特定于您的问题:

      来自 java 文档,

      注意,一般需要重写hashCode方法 每当 equals() 方法被覆盖时,以保持一般 hashCode 方法的契约,它规定相等的对象必须 具有相同的哈希码。

      Equals

      【讨论】:

      • 这通常是正确的,但 equals 和 hashcode 确实意味着一致:默认选择一个或两个都覆盖,使它们不一致(仅覆盖其中一个)是一个重要的设计决策。
      • 我觉得现在我的回答有点意思了。
      猜你喜欢
      • 1970-01-01
      • 2014-07-01
      • 2020-06-06
      • 1970-01-01
      • 2019-01-22
      相关资源
      最近更新 更多