我在许多地方读过,虽然在Java中覆盖equals
方法,但也应该覆盖hashCode
方法,否则就是“违反合同”。
但到目前为止,如果我只覆盖equals方法,而不是hashCode方法,那么我没有遇到任何问题。
合同是什么?当我违反合同时,为什么我没有遇到任何问题?如果我没有覆盖hashCode方法,在哪种情况下我会遇到问题?
答案 0 :(得分:142)
您将遇到的问题是,根据.equals()
和.hashCode()
计算元素的唯一性,例如HashMap
中的键。
顾名思义,它依赖于哈希表,哈希桶是对象.hashCode()
的函数。
如果您有两个.equals()
但具有不同哈希码的对象,则会丢失!
合同中重要的部分是: .equals()
的对象必须具有相同的.hashCode()
。
the javadoc for Object
中记录了这一切。并且Joshua Bloch表示您必须在 Effective Java 中执行此操作。够了。
答案 1 :(得分:14)
根据文档,hashCode的默认实现将返回一些对于每个对象
不同的整数尽可能合理地实现,类Object定义的hashCode方法也是如此 为不同的对象返回不同的整数。 (这通常通过以下方式实现 将对象的内部地址转换为整数,但这个实现
JavaTM编程语言不需要该技术。)
但是有时您希望哈希码对于具有相同含义的不同对象是相同的。例如
Student s1 = new Student("John", 18);
Student s2 = new Student("John", 18);
s1.hashCode() != s2.hashCode(); // With the default implementation of hashCode
如果在集合框架中使用散列数据结构(如HashTable,HashSet),则会出现此类问题。 特别是对于HashSet这样的集合,您最终会遇到重复元素并违反Set契约。
答案 2 :(得分:10)
是的,它应该被覆盖。如果您认为需要覆盖equals()
,则需要覆盖hashCode()
,反之亦然。 hashCode()的一般合同是:
每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终返回相同的整数,前提是不修改对象上的equals比较中使用的信息。从应用程序的一次执行到同一应用程序的另一次执行,此整数不需要保持一致。
如果两个对象根据equals(Object)方法相等,则对两个对象中的每个对象调用hashCode方法必须生成相同的整数结果。
< / LI>- 醇>
如果两个对象根据equals(java.lang.Object)方法不相等,则不需要在两个对象中的每一个上调用hashCode方法必须生成不同的整数结果。但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。
答案 3 :(得分:5)
合同是obj1.equals(obj2)
然后obj1.hashCode() == obj2.hashCode()
,主要是出于性能原因,因为地图主要使用hashCode方法来比较条目键。
答案 4 :(得分:5)
请参阅JavaDoc of java.lang.Object
在hashCode()
中说:
如果根据
equals(Object)
方法两个对象相等, 然后在两个对象中的每一个上调用hashCode
方法必须 产生相同的整数结果。
(我强调)。
如果您只覆盖equals()
而非hashCode()
,则您的班级违反了此合同。
在equals()
方法的JavaDoc中也说过:
请注意,通常需要覆盖
hashCode
方法 每当重写此方法时,都要保持一般hashCode
方法的契约,它声明了相等的对象必须 有相同的哈希码。
答案 5 :(得分:4)
合同是:如果两个对象相等,那么它们应该具有相同的哈希码,如果两个对象不相等,那么它们可能有也可能没有相同的哈希码。
尝试在HashMap中使用您的对象作为键(在joachim-sauer评论后编辑),您将开始遇到麻烦。合同是一个指导方针,而不是强加给你的东西。
答案 6 :(得分:3)
查看Hashtables
,Hashmaps
,HashSets
等等。它们都将散列键存储为键。调用get(Object key)
时,会生成参数的散列并在给定的散列中查找。
当没有覆盖hashCode()
并且密钥实例已经改变时(例如一个完全无关紧要的简单字符串),hashCode()
可能导致2个不同的哈希码对象,导致在map.get()
中找不到您的给定密钥。