在Java中,当覆盖equals
方法时,许多地方都说应该一并覆盖hashCode
方法,否则就会“违反合同”。
但到目前为止,如果我只覆盖了equals方法而没有覆盖hashCode方法,我还没有遇到任何问题。
什么是这个“合同”?为什么我没有遇到问题却违反了它?如果我没有覆盖hashCode方法,在哪种情况下会出现问题?
在Java中,当覆盖equals
方法时,许多地方都说应该一并覆盖hashCode
方法,否则就会“违反合同”。
但到目前为止,如果我只覆盖了equals方法而没有覆盖hashCode方法,我还没有遇到任何问题。
什么是这个“合同”?为什么我没有遇到问题却违反了它?如果我没有覆盖hashCode方法,在哪种情况下会出现问题?
.equals()
和.hashCode()
计算的,例如HashMap
中的键。.hashCode()
函数。.equals()
,但具有不同的哈希码,那么你就会损失!.equals()
的对象必须具有相同的.hashCode()
。==
)。 - fgeStudent s1 = new Student("John", 18);
Student s2 = new Student("John", 18);
s1.hashCode() != s2.hashCode(); // With the default implementation of hashCode
是的,它应该被覆盖。如果您认为需要重写equals()
,那么您需要重写hashCode()
,反之亦然。 hashCode() 的一般契约是:
在Java应用程序的执行过程中,如果同一对象被多次调用,则hashCode方法必须始终返回相同的整数,前提是未修改用于在对象上进行equals比较的任何信息。这个整数不需要从一个应用程序的执行到另一个应用程序的执行保持一致。
如果两个对象根据equals(Object)方法是相等的,则在每个对象上调用hashCode方法必须产生相同的整数结果。
不要求如果根据equals(java.lang.Object)方法两个对象不相等,则在每个对象上调用hashCode方法必须产生不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。
Hashtables
、Hashmaps
、HashSets
等等。它们都将散列后的键作为它们的键存储。在调用 get(Object key)
时,参数的哈希值将被生成并在给定的哈希值中查找。hashCode()
并且键的实例已被更改(例如一个简单的字符串根本不重要),hashCode()
可能会对同一对象产生两个不同的哈希码,导致无法在 map.get()
中找到您提供的键。这个约定是如果obj1.equals(obj2)
,那么obj1.hashCode() == obj2.hashCode()
,主要是为了提高性能,因为映射(maps)主要使用hashCode方法来比较条目(entries)的键(keys)。
在hashCode()
中,它说:
如果两个对象根据
equals(Object)
方法是相等的,则在这两个对象上调用hashCode
方法必须产生相同的整数结果。
(由我强调)。
如果您仅覆盖equals()
而不是hashCode()
,则您的类将违反此契约。
这也在equals()
方法的JavaDoc文档中提到:
hashCode
方法,以便在覆盖此方法时维护hashCode
方法的一般契约,该契约规定相等的对象必须具有相等的哈希码。一个合同是:如果两个对象相等,则它们应该具有相同的哈希码;如果两个对象不相等,则它们可能具有相同的哈希码,也可能没有。
尝试将您的对象用作HashMap中的键(在joachim-sauer的评论后编辑),您将开始遇到麻烦。合同是一种指导方针,而不是强制性规定。
HashMap
中使用这样的对象时,这正是发生的事情。 - Joachim Sauer