必须同时重写equals和hashCode方法——因为HashMap先用hashCode定位桶,再用equals比对;若不一致,会导致查找不到或性能退化,且需保证相等对象哈希值相同、参与equals的字段必须参与hashCode计算、key字段不可变、注意null安全。

要让自定义对象在 HashMap 中作为 key 正确工作,必须同时、一致地重写 equals 和 hashCode 方法——这不是可选项,而是 Java 集合框架的硬性契约。
为什么必须同时重写
HashMap 查找 key 分两步:先用 hashCode() 定位桶(bucket),再在该桶内用 equals() 逐个比对。如果只重写 equals,两个逻辑相等的对象可能因默认 hashCode(基于内存地址)不同而散列到不同桶中,get() 永远找不到;如果只重写 hashCode,所有对象哈希值相同,全挤在一个桶里,退化为链表遍历,且 equals 仍按引用判断,逻辑相等的对象仍被视为不同。
核心规范要点
-
一致性前提:只要
obj1.equals(obj2)返回true,那么obj1.hashCode() == obj2.hashCode()必须为true -
字段同步:参与
equals判断的每一个字段,都必须参与hashCode计算;反之,hashCode中不能出现equals未使用的字段 -
不可变保障:一旦对象被放入
HashMap作 key,其用于equals和hashCode的字段就不能再修改,否则哈希桶位置与当前值不匹配,导致查不到、删不掉 -
null 安全:
equals方法中需显式检查null,推荐用Objects.equals(a, b);hashCode推荐用Objects.hash(f1, f2, ...),它自动处理null
正确写法示例(以 Person 类为例)
假设业务上认为 id 和 name 相同即为同一人:
→ equals 写法关键步骤:
立即学习“Java免费学习笔记(深入)”;
- 先用
this == obj快速判同一引用 - 再检查
obj == null || getClass() != obj.getClass() - 强转后用
Objects.equals(id, other.id) && Objects.equals(name, other.name)
→ hashCode 写法关键步骤:
- 直接返回
Objects.hash(id, name),简洁、安全、分布合理 - 避免手写
31 * id + name.hashCode()等易错公式 - 绝对不要返回固定值(如
return 1;)或随机值
验证是否生效的简单测试
别靠“没报错”判断,用这两行代码实测:
map.put(p1, "v1"); System.out.println(map.get(p2)); // 应输出 "v1"System.out.println(map.size()); // 应输出 1,不是 2
不复杂但容易忽略。


















