重写 hashCode 的核心原则是:相等对象必须有相同哈希码,但哈希码相同不保证相等;必须与 equals 同时重写,且仅基于 equals 中使用的不可变字段计算,推荐用 Objects.hash(...)。

重写 hashCode 方法的核心原则是:**只要两个对象通过 equals 判定为相等,它们的 hashCode 就必须相同;但 hashCode 相同,不意味着 equals 一定为 true**。这是哈希表(如 HashMap、HashSet)正确工作的前提。
必须同时重写 equals 和 hashCode
只重写其中一个会导致行为不一致。Java 规定:equals 和 hashCode 必须保持逻辑一致。如果用自定义类作 HashMap 的 key 或 HashSet 的元素,而没重写这两个方法,那默认使用 Object 的实现(基于内存地址),会导致:
- 内容相同的对象被当作不同 key,存入多个副本
-
contains、get等操作失效
重写 hashCode 的常用方式
推荐使用 JDK 7+ 引入的 Objects.hash(...),它自动处理 null,并对多个字段组合计算哈希值,简洁安全:
public class Person {
private String name;
private int age;
private String idCard;
<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); // ✅ 推荐写法
}
}
手动计算 hashCode 的注意事项
若不用 Objects.hash,需手动组合字段哈希值,常见模式是:
- 以非零常数(如 17)为初始值
- 对每个参与比较的字段:用当前结果 × 31 + 字段的 hashCode
- 字符串、包装类、数组等直接调用其
hashCode();null 值要显式处理(如用 0)
例如:
@Override
public int hashCode() {
int result = 17;
result = 31 * result + (name == null ? 0 : name.hashCode());
result = 31 * result + age;
result = 31 * result + (idCard == null ? 0 : idCard.hashCode());
return result;
}注意:31 是个常用质数,能较好分散哈希值,避免乘法溢出过早发生,但不是强制要求。
避免踩坑的关键点
-
只包含参与 equals 比较的字段:如果某个字段没在
equals中使用,就不该出现在hashCode计算中 -
字段值不可变(或确保 hash 不变):若对象放入
HashMap后修改了影响hashCode的字段,会导致无法再 get 到该 key(因为查找去了错误的桶) - 不要在 hashCode 中调用可能抛异常或依赖外部状态的方法:比如数据库查询、文件读取
- 性能不必过度优化:只要逻辑正确、分布相对均匀即可;JDK 已经做了足够好的散列设计
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











