首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

為什麼重寫 equals 必須重寫 hashCode?契約、哈希表原理與最佳實踐

     編輯:Java 程式設計入門

核心契約

  1. 一致性:a.equals(b) == true ⇒ a.hashCode() == b.hashCode()
  2. 非唯一性:hashCode 相等 ⇏ equals 相等(哈希碰撞)

底層原理:HashMap 存取流程

  1. 計算 key.hashCode() 確定桶索引 (n-1) & hash
  2. 桶內遍歷鏈表/紅黑樹,調用 equals 比較
  3. 若未重寫 hashCode,邏輯相等對象落入不同桶,**導致無法查找、重複插入**

反面教材

class Bad {
    String name;
    @Override public boolean equals(Object o) {
        return o instanceof Bad && name.equals(((Bad)o).name);
    }
    // 缺失 hashCode → 繼承 Object.identityHashCode()
}

Set set = new HashSet<>();
set.add(new Bad("A"));
set.add(new Bad("A")); // 邏輯相等,但 hashCode 不同
System.out.println(set.size()); // 輸出 2!違反 Set 語義

正確實現模板

@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) && age == p.age;
}

@Override
public int hashCode() {
    return Objects.hash(name, age); // JDK 7+ 推薦
    // 手動實現:31 * name.hashCode() + age
}

IDE 生成與庫支援

  • IntelliJ IDEA:Alt+Insert → equals() and hashCode()
  • Lombok:@EqualsAndHashCode 自動生成
  • Guava:Objects.hashCode()、MoreObjects.toStringHelper()

不可變對象優勢

若類不可變,hashCode 可緩存(如 String),提升性能;作為 Map Key/Set 元素安全可靠。

總結

  • 「equals 相等 ⇒ hashCode 相等」是**硬性規範**,違反即導致集合失效
  • 始終成對重寫,使用 Objects.hash 或 IDE 生成
  • 字段選擇:equals 用哪些字段,hashCode 就用哪些
  • 避免在 equals 中使用非確定性計算
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved