在java中,自定义对象作hashmap键时,必须同时重写equals()和hashcode()方法,且二者须基于同一组不可变字段计算,确保逻辑相等的对象具有相同哈希值,否则put()和get()将失效。

在 Java 中,用自定义对象作 HashMap 的键,核心是保证:只要两个对象逻辑上“相等”,它们的 hashCode() 就必须相同;且 equals() 和 hashCode() 的判断依据必须完全一致。否则,put() 和 get() 会出错——比如明明存了,却 get() 不出来。
必须同时重写 equals 和 hashCode
只重写 equals() 而不重写 hashCode(),会导致相同对象算出不同哈希值,被散列到不同桶中,get() 时根本找不到;反之,只重写 hashCode() 而 equals() 还用默认(即引用比较),那即使哈希值相同,也永远不会判定为相等,查不到结果。
- 二者必须基于同一组字段计算(比如都只看
id和name) - 字段值一旦用于判断相等性,就不能在对象放入 Map 后修改(否则哈希桶位置失效)
- 推荐用 IDE 自动生成(如 IntelliJ 的
Alt+Insert → equals and hashCode),避免手写疏漏
字段选择要稳定且符合业务语义
选哪些字段参与 equals() 和 hashCode(),取决于你“认为什么才算同一个键”。例如:
- 用户类用
userId唯一标识,那就只用userId;加了name反而导致同 ID 不同名就视为不同键 - 订单类若用
orderNo+storeId联合唯一,这两个字段就得一起参与 - 避免使用可变字段(如
status、lastModified),否则对象入 Map 后改了状态,哈希值变了,原位置就找不到了
注意 null 值的安全处理
如果参与比较的字段可能为 null,别直接调 field.equals(),容易空指针。标准写法是:
- 用
Objects.equals(a, b)替代a.equals(b)(自动处理 null) - 用
Objects.hash(f1, f2, ...)生成哈希值(内部对 null 返回 0) - 手动写时,对每个字段判空再比较,哈希计算用三元运算符(如
field == null ? 0 : field.hashCode())
验证是否生效的小技巧
写完后,用最简测试确认行为正确:
- 创建两个字段值完全相同的对象
a和b,检查a.equals(b)是否为true,a.hashCode() == b.hashCode()是否为true - 把
a放进HashMap,再用b去get(),看能否取到值 - 故意让一个字段不同,确认
equals()返回false,且哈希值大概率不同(不要依赖“一定不同”,哈希碰撞合法)
不复杂但容易忽略细节,关键是保持 equals 和 hashCode 的一致性,并让参与的字段真正代表“键的唯一性”。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











