【发布时间】:2013-01-24 17:03:33
【问题描述】:
我的同事重写了equals() 方法。我的回答是,你是否也覆盖了hashCode() 方法?他的回答是因为我们不会使用散列映射或散列集,如果我们覆盖hashCode() 并不重要。对吗?
【问题讨论】:
我的同事重写了equals() 方法。我的回答是,你是否也覆盖了hashCode() 方法?他的回答是因为我们不会使用散列映射或散列集,如果我们覆盖hashCode() 并不重要。对吗?
【问题讨论】:
是的,事实上他是对的——但是,如果有一天你需要将你的对象放在一个基于哈希的集合中,你将不得不在任何地方添加哈希码,这可能会很烦人 + 那天你可能会错误地实现你的哈希码(即与equals不一致)因为你错过了equals方法中的一些微妙之处......
考虑到大多数 IDE 都提供自动 equals/hashcode 生成功能,我认为没有理由不同时创建两者。
另一种看待它的方式是:当您从父类重写方法时,您应该遵循该父类定义的协定。在 Object 的情况下,javadoc of equals 非常清楚:
请注意,通常需要在任何时候重写 hashCode 方法,以维护 hashCode 方法的一般约定,即相等的对象必须具有相等的哈希码。
因此,除非您有真正的设计理由不覆盖哈希码,否则默认决定应该是遵循父类契约并且不覆盖或覆盖两者。
【讨论】:
equals 是代码现在所依赖的,那么 hashCode 很有可能落后于 equals 的更改,再次结束与它不一致。在我看来,最好的折衷方案是简单的return 1;——至少它在技术上是正确的。
HashSet,它似乎可能会导致静默、难以调试的性能问题。相反,我将hashCode() 实现为throw new UnsupportedOperationException(),这需要最少的努力,但是当您稍后返回并使用HashSet 时,很明显您没有费心第一次实现hashCode()。跨度>
hashCode() 方法添加回他覆盖equals() 的那个类吗?
如果您覆盖equals(),请同时覆盖hashCode()。即使您现在不使用hashCode(),您或其他人也可能会使用它。
有关此主题的更多信息,请查看优秀的SO answer
【讨论】:
这是一种代码味道。例如,如果您覆盖 hashCode 或 equals 而不覆盖另一个,Findbugs 会警告您。您应该覆盖两者,以使它们彼此一致(即 a.equals(b) => a.hashCode() == b.hashCode())。
现在稍加努力,以后可能会省去很多麻烦。
【讨论】:
hashCode() 抛出异常)。我知道使用 hashCode 来测试 null 的代码(即期待 NPE)[伪造的 getClass() 会更好] - 所以再次可能没问题 - 但提出默认设置有点冒险。
您必须在每个覆盖 equals 的类中覆盖 hashCode。否则将导致违反 Object.hashCode 的一般约定,这将阻止您的类与所有基于哈希的集合(包括 HashMap、HashSet 和 Hashtable)一起正常运行。
Effective Java Item 9:当你覆盖 equals 时,总是覆盖 hashCode。
如果您的课程是公共课程,那么您无法控制您的课程在未来开发中的使用方式。如果不查看源代码(或通过反射),就无法知道这个类是否覆盖了 hasCode 方法,如果用户在任何基于散列的集合中使用它,用户会对结果感到惊讶。
【讨论】:
实际上假设您创建了两个不同的对象,而没有覆盖 equals 和 hashCode 方法。然后如果你调用 equals 方法 java 隐式调用 hashCode 方法然后检查 hashcode 的相等性。
重写 hashCode 方法足以检查两个对象的相等性。它对未来很有用。你可以在集合上使用这个类。
否则如果你只实现equal方法,它只会解决两个对象的相等问题。
【讨论】:
hashCode 来实现equals 的默认实现。它使用== 验证两个对象指向同一个引用。你可以让hashCode 在每次调用时返回一个随机值,如果你指向同一个对象,equals 的默认实现仍然有效。
一般:
只覆盖那些您想以自己的方式使用的方法,以及那些受此覆盖影响的方法。
特定于您的问题:
来自 java 文档,
注意,一般需要重写hashCode方法 每当 equals() 方法被覆盖时,以保持一般 hashCode 方法的契约,它规定相等的对象必须 具有相同的哈希码。
【讨论】: