跳转至

为什么要重写 hashCode 和 equals 方法?

结论

不重写会违反"相等的对象必须有相等的哈希码"约定,导致在 HashMap、HashSet、HashTable 中行为异常。

约定(Java 官方规范)

  1. 一致性:同一个对象多次调用 hashCode,必须返回同一个 int。
  2. 相等则哈希相等a.equals(b) == true,则 a.hashCode() == b.hashCode()
  3. 不相等则哈希可以相等(哈希碰撞允许),但尽量不相等以提高散列性能。

不重写会出什么问题

Object 默认的 equals==(比较地址),hashCode 是对象内存地址派生的 int。这意味着:

class Person {
    String name;
    Person(String name) { this.name = name; }
}

Person p1 = new Person("Alice");
Person p2 = new Person("Alice");

HashMap<Person, Integer> map = new HashMap<>();
map.put(p1, 1);
map.get(p2);   // 返回 null!p1 和 p2 是两个对象,hashCode 不同

p1p2 逻辑上是同一个人,但因为没重写 hashCode,HashMap 把它们分到了不同桶。

正确做法

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (!(o instanceof Person)) return false;
    Person p = (Person) o;
    return Objects.equals(name, p.name);
}

@Override
public int hashCode() {
    return Objects.hash(name);
}

工程实践

  • IDE(IDEA/Eclipse)可一键生成。
  • Lombok 的 @Data / @EqualsAndHashCode 自动生成。
  • 重写时必须同时重写两者,不能只重写一个。
  • 用作 HashMap key 的对象,equals 用到的字段必须是不可变的,否则 put 后修改字段会导致 get 不到。