为什么重写 equals 时一定要重写 hashCode?

发布于

一、先说结论

这是 Java 的通用约定:如果两个对象通过 equals 比较相等,那么它们的 hashCode 必须相同。只重写 equals 不重写 hashCode,会破坏这个约定,导致对象在 HashMap、HashSet 等集合中行为异常。

二、HashMap 的存取过程

HashMap 先根据 key 的 hashCode 定位哈希桶,再在桶内通过 equals 判断 key 是否相等:

  1. put:hashCode → 找桶 → 桶内 equals 比较 → 决定覆盖还是新增。
  2. get:同样先算 hashCode 找桶,再用 equals 匹配。

三、不重写会出什么问题

假设只重写了 equals(按业务字段比较内容),而用默认的 hashCode(基于对象地址):

Map<User, String> map = new HashMap<>();
map.put(new User(1L, "张三"), "data");

// 另一个内容相等的对象去查
String v = map.get(new User(1L, "张三")); // null!

两个对象 equals 相等但 hashCode 不同,get 时定位到了不同的桶,自然找不到。

四、正确做法

  • 两个对象 equals 为 true → hashCode 必须相等。
  • hashCode 相等的对象,equals 不一定为 true(允许哈希冲突)。
  • 现代项目建议直接用 IDE 生成,或用 Lombok 的 @EqualsAndHashCode。