必须重写equals和hashcode方法,因为hashmap先用hashcode定位桶、再用equals比对桶内元素;若不重写,相同逻辑对象因内存地址不同被视为不同key,导致查不到值或重复插入。

自定义对象作为 HashMap 的 Key,必须重写 equals 和 hashCode,否则默认使用 Object 的实现(基于内存地址),会导致相同逻辑的两个对象被视为不同 Key,查不到值、重复插入等问题。
为什么必须重写这两个方法?
HashMap 查找 Key 时:先用 hashCode() 定位到桶(bucket),再用 equals() 在该桶内逐个比对。如果只重写 equals 不重写 hashCode,相同对象可能被散列到不同桶里,get() 就永远找不到;反之,如果只重写 hashCode,但 equals 仍用默认实现,两个字段相同的对象仍不相等,也无法命中。
重写规则要严格遵守
必须保证:相等的对象(equals 返回 true)必须有相同的 hashCode 值;反过来不要求(不同对象可以有相同 hash,即哈希碰撞,这是正常的)。
- 所有参与
equals比较的字段,也必须参与hashCode计算 - 字段值为
null时,Objects.equals(a, b)和Objects.hash(...)能安全处理,推荐直接使用 - 字段一旦用于计算 hash 和 equals,就不该在对象放入 HashMap 后修改(否则导致无法查找)
一个标准写法示例
假设有一个表示用户 ID 和姓名的类:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
public class UserKey {
private final Long id;
private final String name;
public UserKey(Long id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UserKey userKey = (UserKey) o;
return Objects.equals(id, userKey.id) &&
Objects.equals(name, userKey.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
}
注意:id 和 name 都声明为 final,避免后续修改破坏 hash 一致性;使用 Objects.equals 和 Objects.hash 简洁且 null-safe。
验证是否生效的小技巧
写个简单测试确认行为正确:
Map<userkey string> map = new HashMap(); map.put(new UserKey(1L, "Alice"), "admin"); // 用另一个“内容相同”的对象去 get String value = map.get(new UserKey(1L, "Alice")); // 应该返回 "admin",不是 null System.out.println(value); // 输出:admin</userkey>
如果输出 null,说明 equals 或 hashCode 写错了,重点检查字段是否完全一致、null 处理是否到位、是否漏掉某个参与比较的字段。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










