必须同时重写 hashcode() 和 equals() 方法,否则 hashmap 会出现存入后无法获取或删除的问题;二者需遵守相等对象哈希值相同的契约,且参与计算的字段应不可变,推荐使用 objects.equals() 和 objects.hash() 实现。

因为 HashMap 查找 key 时,是“先定位、再确认”:先用 hashCode() 算出哈希桶位置,再用 equals() 在该桶内逐个比对是否真相同。如果只重写一个,两个环节的判断逻辑就脱节了,key 就会存得进、取不出、删不掉。
HashMap 的查找机制决定了二者必须协同
HashMap 内部是一个数组加链表/红黑树的结构。当你调用 map.get(key) 时:
- 第一步:调用
key.hashCode(),得到一个整数,再经过扰动运算和取模,算出它应该落在哪个数组索引(桶)里; - 第二步:只在那个桶里的元素中,用
key.equals(已有key)逐个比较,找到真正相等的那个 Entry。
如果自定义类没重写这两个方法,用的就是 Object 默认实现——hashCode() 返回内存地址哈希值,equals() 用 == 比较地址。结果就是:两个内容完全一样的对象(比如 new Person("张三", 25) 两次),hashCode 不同 → 被分到不同桶;即使误落到同一桶,equals 也返回 false → 找不到。
违反契约会导致行为异常
Java 规定:只要 equals() 返回 true,hashCode() 就必须返回相同值。这是哈希集合正常工作的前提。否则会出现:
-
map.put(k1, v1); map.put(k2, v2);—— 本应覆盖,却变成两个键共存; -
map.get(k1)返回 null —— 明明存过,却查不到; -
set.remove(k)失败 —— 对象还在集合里,删不掉。
重写时还要注意字段不可变
参与 hashCode() 和 equals() 计算的字段,必须是 final 的,或确保作为 key 期间绝不修改。例如:
- ✅ 推荐:用不可变 id 字段,如
return Objects.hash(id); - ❌ 危险:用可变的 name 字段,之后改了 name,hashCode 变了,但对象还卡在旧桶里,再也找不到了。
实际写法要兼顾安全与简洁
不必手算复杂公式,用 JDK 提供的工具更可靠:
-
Objects.equals(a, b)安全处理 null; -
Objects.hash(field1, field2, ...)自动生成符合契约的 hashCode; - 记得加上
@Override注解,避免拼写错误导致重写失败。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











