如果我有一个具有坚实,有意义的equals()
方法但缺少补充hashCode()
方法的对象(即bean),那么“最坏情况”后果(这里的真实场景)是什么?方法?似乎大多数API使用equals()
和compareTo()
方法来维护集合。我想知道hashCode()
什么时候最重要?
答案 0 :(得分:6)
最糟糕的后果是哈希表不起作用。例如,假设你有一个像这样的简单类:
public class StringWrapper {
private String value;
...
public boolean equals(Object other) {
// two objects are equal if their respective values are equal ... using `equals`.
}
// No hashcode override.
}
这里我们有一个类,我们有一个类不服从equals / hashcode契约的必需不变量之一。具体来说,两个实例cal相等,但具有不同的哈希码。
当您将此类的两个不同实例添加到HashSet时,可能以不同哈希链中的集合中的两个实例结束。从集合中删除对象时,会出现类似的异常,测试集合是否包含对象,等等。
(请注意,你可能会很幸运,尽管有不同的哈希码,但两个实例最终会在同一个哈希链上。但是当一些其他无关的对象被添加到哈希表时,你的运气会改变,导致它自动调整大小.resize可能会导致具有不同哈希码的条目被重新分配到不同的哈希链。)
所以我想知道...哈希码什么时候最重要?
这一点很重要。
或者换句话说,当您100%确定地知道该类的实例从未将在哈希表中使用时,它只是不重要。 (而且我不知道你怎么知道这一点,除非你删除了所有课程的副本。这使得整个问题没有实际意义!)
<强>更新强>
@supercat提到了你不能写一个像样的哈希码的情况。
如果有一个很好的理由你不能写出一个不太合适的hashcode()
方法,我主张覆盖它来抛出UnsupportedOperationException
或其他一些方法。这样,如果有人试图将实例放入哈希表中,而不是神秘的性能黑洞,那么你会遇到快速失败。 (我不建议返回一个常量哈希码。)
有一个相关的场景,您可能会这样做:当对象固有可变时,并且您希望避免在改变哈希键以使其哈希码发生更改时发生的错误。 / p>
答案 1 :(得分:1)
如果你要关注其中任何一个,你真的,真的应该(需要)实现/覆盖两者。有关详细信息,请参阅Why do I need to override the equals and hashCode methods in Java?,包括如果未通过正确的相关实现实现这些功能,可能会发生什么。
此外,从another answer那里:
您必须覆盖覆盖equals()的每个类中的hashCode()。 如果不这样做将导致违反总承包合同 对于Object.hashCode(),它将阻止您的类运行 正确地与所有基于散列的集合一起使用,包括 HashMap,HashSet和Hashtable。
来自Effective Java的,来自Joshua Bloch
答案 2 :(得分:0)
此方法返回调用此方法的对象的哈希码值。此方法将哈希码值作为整数返回,并且支持基于哈希的集合类(如Hashtable,HashMap,HashSet等)的优势。必须在覆盖equals方法的每个类中重写此方法。