必须重写hashCode()和equals()方法,因为HashMap先用hashCode定位桶再用equals比对;只重写其一会导致查找失败或数据覆盖;应基于相同字段计算且保证对象不可变。

要让自定义对象作为 HashMap 的键,核心是正确重写 hashCode() 和 equals(Object obj) 方法。否则,即使两个对象逻辑上相等,HashMap 也无法正确识别、查找或覆盖。
为什么必须重写 hashCode 和 equals
HashMap 查找键时,先用 hashCode() 定位桶(bucket)位置,再用 equals() 在该桶内逐个比对。如果只重写 equals 而不重写 hashCode,相等的对象可能散列到不同桶中,导致 get() 返回 null;如果只重写 hashCode 而不重写 equals,不同对象可能被误判为相同键,造成数据覆盖或丢失。
如何正确重写这两个方法
推荐使用 IDE 自动生成(如 IntelliJ 的 Alt + Insert → Equals and hashCode),或使用 Objects.hash(...) 和 Objects.equals(...) 手动编写,确保逻辑一致:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
-
hashCode:只基于参与
equals判断的字段计算,且这些字段在对象存入HashMap后不应被修改(否则哈希值变化,键将“丢失”) -
equals:先用
==判断引用相等,再用instanceof检查类型,最后逐个用Objects.equals()比较关键字段 - 保持对称性、传递性、一致性,并确保对
null安全
一个典型示例
假设用 User 对象作键,以姓名和年龄为唯一标识:
立即学习“Java免费学习笔记(深入)”;
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return age == user.age && Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
之后即可正常使用:
Map<User, String> map = new HashMap<>();
map.put(new User("Alice", 25), "Engineer");
System.out.println(map.get(new User("Alice", 25))); // 输出 "Engineer"
重要注意事项
- 键对象的字段一旦放入
HashMap,就应视为不可变(immutable)。若修改了影响hashCode或equals的字段,该键将无法被正常访问 - 若需可变键,建议改用其他结构(如
TreeMap配合Comparator),或确保修改后手动remove再put - 避免在
hashCode中使用随机数、当前时间等非稳定值

















