必须同时重写且逻辑一致:若a.equals(b)为true,则a.hashcode()必须等于b.hashcode();hashmap先用hashcode定位桶,再用equals精确匹配,否则存入后无法获取。

要让自定义对象顺利、可靠地作为键放入 HashMap,equals 和 hashCode 必须严格协同:不是“最好一起写”,而是“必须同时重写且逻辑一致”。否则,对象可能存得进去却取不出来,或看似相同却重复插入。
核心协同规则:相等必同哈希
这是 Java 规范的硬性要求:
- 如果
a.equals(b) == true,那么a.hashCode() == b.hashCode()必须成立 - 反之不成立:哈希值相同,
equals可以为false(这是正常哈希冲突) - 违反第一条,
HashMap就会“失联”——put 进去了,get 却返回null
HashMap 查找时的真实流程
理解这个过程,就能明白为什么缺一不可:
- 调用
map.get(key)时,先算key.hashCode(),根据结果定位到某个桶(数组索引) - 只在这个桶里遍历节点,对每个节点的 key 调用
key.equals(传入的 key) - 如果
hashCode算错,key 被放到了 A 桶;而你用另一个逻辑相等的对象去 get,它算出的是 B 桶——根本不会去 A 桶翻找,直接返回null
重写时的关键实操要点
光知道规则不够,落地要避开常见坑:
- 参与
equals比较的字段,一个都不能少地用于hashCode计算(例如用Objects.hash(id, name)) - 排除可变字段:如
status、lastModifiedTime、cacheValue—— 一旦对象加入HashMap后修改它们,哈希桶位置就“失效”了 - 用
Objects.equals(a, b)写equals,自动处理null安全;别手写a == null ? b == null : a.equals(b) - IDE 生成后务必检查:确认勾选的字段完全一致,且引用类型(如嵌套对象、集合)自身也已正确重写这两个方法
一个典型反例说明问题
假设 User 类只重写了 equals(比较 id 和 name),但没动 hashCode:
-
user1 = new User(100, "Alice")→ 放进map.put(user1, "admin") -
user2 = new User(100, "Alice")→user1.equals(user2)为true - 但
user2.hashCode()是默认内存地址哈希,和user1不同 →map.get(user2)返回null
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











