重写 hashCode 方法的核心原则是:只要两个对象通过 equals 判定为相等,它们的 hashCode 就必须相同;反之不强制要求。这是 Java 规范对哈希表正确工作的基本约束,需与 equals 保持一致,推荐使用 Objects.hash(...) 或按 31 * result + field.hashCode() 手动计算,且仅包含参与 equals 比较的不可变字段。

重写 hashCode 方法的核心原则是:**只要两个对象通过 equals 判定为相等,它们的 hashCode 就必须相同;反之不强制要求。** 这是 Java 规范对哈希表(如 HashMap、HashSet)正确工作的基本约束。
为什么必须和 equals 保持一致
如果只重写了 equals 却没重写 hashCode,默认继承自 Object 的 hashCode 返回的是对象内存地址的哈希值。此时即使两个逻辑上相等的对象(equals 返回 true),也会因哈希值不同被散列到哈希表的不同桶中,导致 contains 找不到、put 重复插入等问题。
怎么写一个合格的 hashCode
推荐使用 JDK 7+ 提供的 Objects.hash(...) 工具方法,它会自动处理 null 值,并基于传入字段计算组合哈希值:
// 示例:Person 类
public class Person {
private String name;
private int age;
private String idCard; // 可能为 null
<pre class="brush:php;toolbar:false;">@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name) &&
Objects.equals(idCard, person.idCard);
}
@Override
public int hashCode() {
return Objects.hash(name, age, idCard); // 简洁安全,自动处理 null
}}
手动计算 hashCode 的要点
若不用 Objects.hash,可按以下方式手写(以 name、age、idCard 为例):
- 起始值通常用非零常量(如
17),避免全零字段导致哈希值恒为 0 - 每加入一个字段,用
result = 31 * result + field.hashCode()累积(31是奇素数,能较好打散哈希分布) - 对引用类型字段,先判空再调用
hashCode();基本类型直接用其值;boolean建议转为1/0 - 数组需用
Arrays.hashCode(arr),不能直接调用arr.hashCode()(那是引用哈希)
哪些字段该参与 hashCode 计算
只应包含那些参与 equals 比较的字段 —— 也就是决定对象“逻辑身份”的字段。
- ✅ 正确:身份证号、用户名、订单编号等唯一标识字段
- ❌ 错误:临时计算结果、缓存字段、数据库主键(若未参与 equals)、
transient字段(除非业务明确需要) - ⚠️ 注意:如果字段在对象生命周期中可变(如 setter 修改了
name),且该对象已放入哈希集合,则修改后可能无法被找到 —— 所以建议将参与hashCode和equals的字段设为final
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











