Skip to content
极高进阶

一句话答案

重写 equals 必须重写 hashCode,相等对象 hashCode 必须相同,HashMap 先比较 hashCode 再比较 equals。

核心要点

原因:equals()hashCode() 之间有契约(Contract):

如果两个对象 equals() 返回 true,则它们的 hashCode() 必须相同。

如果只重写 equals() 不重写 hashCode()

java
class Person {
    String name;
    @Override
    public boolean equals(Object o) {
        return this.name.equals(((Person) o).name);
    }
    // 没有重写 hashCode(),使用默认的 Object.hashCode()(基于内存地址)
}

Person p1 = new Person("Alice");
Person p2 = new Person("Alice");

p1.equals(p2);  // true(重写了 equals)
p1.hashCode() == p2.hashCode();  // false!(内存地址不同)

// 放入 HashMap 后出问题:
Map<Person, String> map = new HashMap<>();
map.put(p1, "value");
map.get(p2);  // 返回 null!因为 p2 的 hashCode 不同,定位到错误的桶

HashMap 的查找流程:

  1. 计算 key 的 hashCode() → 定位桶位置
  2. 在桶中用 equals() 逐个比较

如果 hashCode() 不一致,第一步就定位错误,永远找不到对应的 key。

正确做法:

java
@Override
public int hashCode() {
    return Objects.hash(name);  // 基于 name 计算,保证 equals 相同时 hashCode 也相同
}
追问与易错

追问方向:

  • 为什么重写 equals 必须重写 hashCode?(HashMap 先比 hashCode 再比 equals)
  • hashCode 相同 equals 一定相同吗?(不一定,哈希碰撞)
  • HashMap 中 key 的 hashCode 变了会怎样?(找不到原来的 entry,内存泄漏)

易错点:

  • ❌ 反过来说"equals 相等 hashCode 可以不同"——这会违反契约,HashMap 行为异常
  • ❌ ��记 null 值处理——equals 实现中要处理 null 和类型检查

💡 记忆锚点

HashMap找人两步走:先按hashCode定楼层(桶),再用equals逐户敲门。equals说相等但hashCode指错楼层,就永远敲不到门——所以重写equals必须同步重写hashCode。