『Java 语法基础』对 equals() 和 hashCode() 的理解

为什么在重写 equals 方法的时候需要重写 hashCode 方法
因为有强制的规范指定需要同时重写 hashcode 与 equals 方法,许多容器类,如 HashMap、HashSet 都依赖于 hashcode 与 equals 的规定。
在Java中,equals() 和 hashCode() 方法是 Object 类的两个非常重要的方法,它们用于比较对象的相等性以及计算对象的哈希码。
equals() 方法用于判断两个对象是否逻辑上相等,也就是两个对象的内容是否相同。它通常需要根据实际情况在子类中重写,以提供正确的相等性逻辑。默认情况下(如 Object 类中的实现),equals() 方法比较对象的内存地址,也就是说,只有同一个对象才被认为是相等的。
hashCode() 方法则用于计算对象的哈希码,它被用于散列数据结构,如 HashSet、HashMap 等。在散列数据结构中,对象的哈希码通常被用来决定对象应该存放的位置。
根据 Java 规范,有关 equals() 和 hashCode() 的重要契约包括:
- 如果两个对象相等,那么它们的
hashCode()方法必须返回相同的整数。 - 如果两个对象的
hashCode()方法返回相同的整数,这并不要求它们一定相等,但散列表的效率可能受到影响。
之所以在重写 equals() 方法时必须同时重写 hashCode() 方法,是为了维持这两个方法之间的一致性。如果两个对象是相等的,但它们的哈希码不相同,这将违反 hashCode() 方法的契约,可能导致无法正确地存取散列数据结构中的对象。例如,在使用 HashMap 时,如果两个键对象相等,它们必须具有相同的哈希码,否则可能会导致其中一个对象无法被正确地找到。
有没有可能两个不相等的对象有相同的 hashcode?
有可能,即使两个对象不相同,它们也可能具有相同的 hashCode 值,这称为哈希冲突。哈希冲突是散列算法的一个固有属性,因为散列码是将对象信息映射到一个有限的整数域上。由于这个整数域范围的限制,相对于可能的对象状态来说是不足够的,从而导致不同对象间的哈希值可能相同。
Java语言规范中关于 hashCode 的合同确实指出,如果两个对象相同,则它们的哈希码一定相同,但并未规定不同的对象必须产生不同的哈希码。因此,在基于哈希的数据结构中,如 HashMap,便可能出现哈希碰撞。在这种情况下,HashMap 会使用 链表 或 红黑树 来管理相同哈希码的不同键,确保了即便发生了哈希碰撞,也能通过 equals() 方法准确地区分和处理这些键。
因此,为了确保诸如 HashMap、HashSet 这样的基于哈希的集合能够正确且高效地运作,合理地实现 hashCode 和 equals 方法以及妥善处理哈希冲突是至关重要的。
两个相同的对象会有不同的 hash code 吗?
不能,根据 hash code 的规定,这是不可能的。
在 Java 中,当你重写一个类的 equals() 方法时,根据 Java 的规范,你也必须重写 hashCode() 方法,以保证同一个类的两个相等的对象(即 equals() 方法返回 true)返回相同的 hash code 值。这是因为 Java 中的集合类,如 HashMap 和 HashSet,依赖于 hashCode() 和 equals() 方法来确定对象的唯一性。
如果两个对象根据 equals(Object) 方法是相等的,那么它们的 hashCode()方 法也必须返回相同的整数值。如果没有重写 hashCode(),那么默认的 Object 类的实现将产生基于对象内存地址的 hash code,这可能会违反这一规定,并且在使用哈希表的过程中导致性能下降。所以重写 equals() 时一定要同步重写 hashCode(),以确保行为的一致性。


浙公网安备 33010602011771号