必须同时重写hashcode,因为java规范要求equals为true的对象hashcode必须相同,否则hashmap、hashset等容器会因散列到不同桶而查找失败或重复插入;且hashcode计算字段必须与equals一致。

Java 中 Object 类的 equals 方法默认确实比较的是对象的内存地址(即引用是否指向同一块堆内存),这通常不符合业务逻辑需求。要让它按“内容相等”判断,必须重写 equals 方法,并且**必须同时重写 hashCode 方法**,否则会破坏哈希集合(如 HashMap、HashSet)的契约。
重写 equals 的核心原则
重写时需满足五个数学性质:自反性、对称性、传递性、一致性、非空性。实际编码中,建议按标准模板来,避免常见陷阱:
- 先用
==判断是否为同一对象(提高效率,也处理 null 情况) - 再用
instanceof或getClass() == obj.getClass()判断类型是否兼容(推荐后者,更严格) - 强制转换后,逐个比较关键字段(注意 null 安全,推荐用
Objects.equals(a, b)) - 基本类型直接用
==,引用类型用Objects.equals
一个典型重写示例
以 Person 类为例,认为姓名和年龄相同即为同一人:
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // 同一引用
if (obj == null || getClass() != obj.getClass()) return false; // 类型不匹配或 null
Person person = (Person) obj;
return age == person.age // 基本类型直接 ==
&& Objects.equals(name, person.name); // 引用类型用 Objects.equals 处理 null
}
@Override
public int hashCode() {
return Objects.hash(name, age); // 与 equals 中使用的字段保持一致
}
为什么必须重写 hashCode?
如果只重写 equals 而不重写 hashCode,会导致:
- 两个逻辑相等的对象(
equals返回 true)可能有不同hashCode - 在
HashMap中,它们可能被散列到不同桶里,导致get()找不到已存入的对象 - 违反了
Object规范:“相等的对象必须有相同的哈希码”
工具和注意事项
现代 IDE(如 IntelliJ IDEA)可一键生成 equals 和 hashCode,但要注意:
- 勾选的字段必须与业务上的“相等定义”完全一致
- 避免包含可变字段(如状态标志),否则对象放入
HashSet后修改字段会导致无法查找 - 若类可被继承,考虑是否用
getClass()(限制子类不能参与比较)还是instanceof(支持多态比较) - Lombok 的
@EqualsAndHashCode可自动处理,但同样需明确指定include或exclude字段
不复杂但容易忽略。关键不是“怎么写”,而是“为什么这么写”——每一步都在维护语义正确性和集合容器的可靠性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











