用自定义对象作HashMap的Key,须重写equals和hashCode且逻辑一致:equals为true时hashCode必须相等;推荐用IDE生成或手动遵循==判同、instanceof校验、Objects.equals比较字段;hashCode用Objects.hash确保与equals字段一致且不可变。

用自定义对象作 HashMap 的 Key,核心就两点:正确重写 equals 和 hashCode,且二者逻辑必须一致——如果两个对象 equals 返回 true,它们的 hashCode 必须相等;反之不强制,但尽量避免冲突。
equals 方法怎么写才安全
推荐用 IDE(如 IntelliJ)自动生成,或手动遵循以下原则:
- 先用
==判断是否为同一对象(性能优化) - 再用
instanceof检查类型,避免 ClassCastException - 强转后,只比较影响“业务上是否相等”的字段(比如 ID、姓名、邮箱等,排除 createTime、status 等非标识性字段)
- 对引用类型字段(如 String、其他自定义对象),用
Objects.equals(a, b)安全比较(自动处理 null) - 基本类型直接用
==,包装类型仍用Objects.equals
hashCode 方法怎么写才合理
目标是:equals 为 true 的对象,hashCode 必须相同;同时尽量让不同对象的 hash 值分布均匀,减少哈希冲突。
- 用
Objects.hash(field1, field2, ...)最省心、最规范(JDK 自带,已处理 null 和散列算法) - 确保参与
hashCode计算的字段,和equals中用于判断相等的字段完全一致 - 不要包含可变字段(比如后面会修改的 status、count),否则对象放入 HashMap 后改了这些字段,就再也找不到了
- 避免手写乘法加法组合(如
31 * a + b),容易出错,也无必要
关键提醒:不可变性很重要
如果对象作为 Key,最好设计成不可变(Immutable):
- 所有参与 equals/hashCode 的字段设为
final - 构造时一次性赋值,不提供 setter
- 如果必须可变,务必保证在 HashMap 中使用期间,这些字段不被修改
否则会出现“存进去找不到”的经典问题:对象存入时 hash 是 A,取的时候字段变了导致 hash 变成 B,HashMap 就去 B 桶里找,自然为空。
一个典型例子(User 类)
// 只有 id 和 name 决定是否为同一个 User
public class User {
private final Long id;
private final String name;
<pre class="brush:php;toolbar:false;">public User(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;
User user = (User) o;
return Objects.equals(id, user.id) &&
Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name); // 和 equals 用的字段严格一致
}}


















