重写 hashCode 方法的核心原则是:只要两个对象通过 equals 判定为相等,它们的 hashCode 就必须相同;必须同时重写 equals 和 hashCode,推荐使用 Objects.hash(...);避免返回固定值、漏算字段或使用可变字段。

重写 hashCode 方法的核心原则是:**只要两个对象通过 equals 判定为相等,它们的 hashCode 就必须相同**;反之则不要求(但尽量不同以提升哈希表性能)。
必须同时重写 equals 和 hashCode
单独重写 hashCode 没有意义,甚至会导致严重问题。Java 规范强制要求:
– 若 a.equals(b) == true,则 a.hashCode() == b.hashCode() 必须成立;
– 若 hashCode 不一致,HashMap、HashSet 等容器会直接把对象分到不同桶中,即使 equals 返回 true 也无法识别为重复,导致去重失效。
推荐写法:用 Objects.hash(...)(JDK 7+)
这是最安全、简洁、不易出错的方式。它自动处理 null,并基于指定字段计算组合哈希值:
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,逻辑与 equals 一致
}}
手动计算 hashCode 的关键细节
如果不用 Objects.hash,需手动构造(不推荐,易错),注意以下几点:
- 起始值通常用非零常量(如
result = 1),避免全零字段导致哈希全为 0 - 对每个参与
equals判定的字段,调用其hashCode()(基本类型用包装类的hashCode,如Integer.hashCode(age)) - 每步用
31 * result + fieldHash组合(31 是奇素数,能减少哈希冲突,且 JVM 会优化成位移减法) - 引用类型字段要判空,否则
field.hashCode()会 NPE;可用field == null ? 0 : field.hashCode()
常见错误示例(务必避免)
❌ 返回固定值(如 return 42;):所有对象哈希相同 → 全挤进一个桶 → 退化为链表遍历,去重仍可能失败(依赖 equals,但性能极差)
❌ 只对部分字段计算哈希(比如漏了 idCard):两个 equals 为 true 的对象哈希不同 → 容器认为是不同对象 → 去重完全失效
❌ 在 hashCode 中使用可变字段(如普通 setter 修改的属性):对象加入 HashSet 后修改字段 → 哈希值改变 → 容器再也找不到它(既不能查也不能删)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











