经典问题
- 为什么重写 equals() 一定要重写 hashcode?
- HashMap 是怎么判断两个对象是否相等的?
- HashMap 为什么要这么做?
一、为什么重写 equals() 一定要重写 hashCode()?
1. Java 官方的硬性契约(必须遵守)
java.lang.Object 类中明确规定了两个方法的共生关系:
- 如果两个对象通过 equals() 比较相等,那么它们的 hashCode()必须返回相同的整数。
- 如果两个对象通过 equals() 比较不相等,它们的 hashCode()可以相同也可以不同(但建议不同,以提高哈希表性能)。
2. 违反契约的后果(以 HashMap 为例)
如果你只重写了 equals() 而没重写 hashCode(),会导致哈希集合(HashMap、HashSet、HashTable 等)逻辑混乱:
- 场景:你创建了两个对象 A 和 B,A.equals(B) == true,但 A.hashCode() != B.hashCode()。
- 存入 HashMap:map.put(A, "value") 会根据 A 的哈希码找到一个位置存入。
- 读取 HashMap:map.get(B) 会根据 B 的哈希码去找(可能找到另一个位置),结果找不到(认为是两个不同的 Key),尽管逻辑上它们是相等的。
二、HashMap 是怎么判断两个对象(Key)是否相等的?
HashMap 判断两个 Key 是否相等,遵循**'先哈希码,后 equals'**的双重检查机制:
- 第一步:比较 hashCode()
- 先调用 Key 对象的 hashCode() 方法,计算哈希值。
- 如果哈希值不同:直接判定两个对象不相等(连 equals 都不用比了,效率高)。
- 如果哈希值相同(哈希碰撞):进入第二步。
- 第二步:比较 equals()
- 调用 Key 对象的 equals() 方法进行内容比对。
- 如果 equals() 返回 true:判定两个对象相等(视为同一个 Key)。
- 如果 equals() 返回 false:判定两个对象不相等(虽然哈希冲突,但仍是不同 Key)。
三、HashMap 为什么要这么设计?
这是为了兼顾性能与准确性,本质是由 HashMap 底层的**'哈希表(数组 + 链表/红黑树)'**数据结构决定的:
1. 为什么要先比 hashCode()?(为了快)
- HashMap 的核心优势是查询速度极快(接近 O(1))。
- 它通过 hashCode 直接计算出 Key 在数组中的存储下标,从而快速定位。
- 如果不先比 hashCode,而是每次都遍历所有元素调用 equals,那性能就退化成了链表(O(n)),失去了哈希表的意义。
2. 为什么还要比 equals()?(为了准)
- :不同的对象可能算出相同的 hashCode(就像不同的人可能有相同的指纹概率)。

