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

Java hashCode() 與 equals() 核心契約深度解析與最佳實踐

     編輯:Java 相關知識

一、equals() 核心規範

Object.equals(Object) 定義物件「邏輯相等」語義,必須滿足 等價關係 五大契約:

  1. 自反性:x.equals(x) == true
  2. 對稱性:x.equals(y) == y.equals(x)
  3. 傳遞性:x.equals(y) && y.equals(z) → x.equals(z)
  4. 一致性:多次呼叫結果不變(前提欄位未改)
  5. 非空性:x.equals(null) == false

標準實作範本

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;           // 同一引用
    if (obj == null) return false;          // 非空性
    if (getClass() != obj.getClass()) return false; // 嚴格類型檢查
    Person other = (Person) obj;
    return Objects.equals(name, other.name) && age == other.age;
}

二、hashCode() 核心契約

  1. 一致性:同一物件多次呼叫返回相同值(未修改 equals 依賴欄位)。
  2. equals 相等 ⇒ hashCode 相等(強制)。
  3. hashCode 相等 ⇏ equals 相等(允許碰撞)。

高效實作範本(Java 7+ Objects.hash)

@Override
public int hashCode() {
    return Objects.hash(name, age); // 內部用 31 為質數乘法組合
}
// 或手寫(避免創建數組/自動裝箱)
@Override
public int hashCode() {
    int h = name == null ? 0 : name.hashCode();
    h = 31 * h + age;
    return h;
}

三、為什麼「同時覆寫」是鐵律?

場景:放入 HashSet/HashMap/Hashtable

Set set = new HashSet<>();
set.add(new Person("Alice", 20));
set.add(new Person("Alice", 20)); // 邏輯相同

// 若只覆寫 equals(),不覆寫 hashCode():
// → 兩物件 hashCode 不同 → 落入不同桶位 → set.size() == 2(錯誤!)
// 正確:同時覆寫 → 同桶位 → equals 判定相等 → set.size() == 1

原理:散列容器先比 hashCode 定桶位,再遍歷桶內鏈表/紅黑樹呼叫 equals。若 hashCode 不同,equals 根本不會被調用。

四、非散列容器場景(ArrayList、Vector、單純比較)

  • 僅靠 equals 判斷相等,hashCode 可不覆寫(繼承 Object 的身份雜湊碼)。
  • 但強烈建議成對覆寫,避免未來誤放入散列容器產生隱性 Bug。

五、常見錯誤模式

錯誤後果修正
equals 用 instanceof 檢查類型破壞對稱性(子類 vs 父類)用 getClass() == obj.getClass() 或 Objects.equals(getClass(), obj.getClass())
equals 比較可變欄位放入 Set/Map 後修改欄位 → 找不到/重複僅用不可變欄位計算 equals/hashCode
hashCode 只用單一欄位碰撞率極高,退化成鏈表 O(n)組合多個關鍵欄位,質數乘法
Arrays.equals 比較陣列欄位忘記處理 null、長度不同用 Arrays.equals(a, b) 或 Objects.deepEquals

六、IDE 自動生成與 Lombok

  • IntelliJ/Eclipse:Generate → equals() and hashCode() 可勾選欄位自動生成標準實作。
  • Lombok:@EqualsAndHashCode(可指定 of、exclude、callSuper)。

七、總結口訣

equals 相等,hashCode 必同;
進散列容器,雙覆寫硬通。
不變欄位算,質數乘法工;
instanceof 別用,getClass 正統。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved