重写 hashCode 的核心目标是确保 equals 返回 true 的对象必须返回相同哈希值,否则在 HashSet、HashMap 中可能无法找到;必须同时重写 equals 和 hashCode,且 hashCode 应基于 equals 中使用的相同字段,避免使用可变字段,并推荐用 Objects.hash() 实现。

重写 hashCode 的核心目标是:**让逻辑上相等的对象(equals 返回 true)必须返回相同的哈希值**,否则它们可能被散列到不同桶中,导致在 HashSet、HashMap 等哈希集合中“找不到”本该存在的对象。
必须同时重写 equals 和 hashCode
这是 Java 的契约要求。如果只重写 hashCode 而不重写 equals,或反之,会导致行为不一致:
-
HashSet查找元素时,先用hashCode()定位桶,再用equals()比较桶内对象; - 若两个对象
equals()为true,但hashCode()不同 → 它们大概率落在不同桶里 →contains()返回false,即使它们“相等”; - 若
hashCode()相同但equals()总返回false→ 可能造成哈希冲突增多,性能下降,但不会破坏正确性。
hashCode 实现要基于 equals 中用到的字段
哪些字段参与了 equals 判断,就用哪些字段计算 hashCode。例如:
public class Person {
private String name;
private int age;
<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);
}
@Override
public int hashCode() {
return Objects.hash(name, age); // ✅ 正确:和 equals 使用相同字段
}}
如果误用未参与 equals 的字段(比如加了 id),或漏掉某个字段(比如只算 name),都会破坏契约。
避免使用可变字段计算 hashCode
一旦对象被放入 HashSet 或作为 HashMap 的 key,它的 hashCode 就不该再变:
- 若修改了影响
hashCode的字段(如name),该对象在哈希表中的位置就“错乱”了; -
HashSet.contains()可能查不到它,remove()失败,甚至导致内存泄漏; - 建议:把参与
hashCode和equals的字段设为final,或确保放入集合后不再修改。
推荐用 Objects.hash() 简化实现
手动组合哈希值容易出错(比如乘数选错、空指针)。Java 7+ 提供了安全便捷的方式:
-
Objects.hash(field1, field2, ...)自动处理null,并采用合理的散列算法; - 不要自己写
name.hashCode() * 31 + age这类表达式(除非你清楚原理且有特殊需求); - IDE(如 IntelliJ)也能自动生成符合规范的
equals和hashCode方法,可直接选用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











