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

Java equals 與 hashCode 契約深度解析:Object、String 實作原理與最佳實務

     編輯:Java 相關知識

Java 核心契約:equals 與 hashCode 完整解析

正確實作 equals() 與 hashCode() 是 Java 開發基礎功力,直接影響 HashMap、HashSet 等集合運作正確性。本文基於 JDK 1.7 原始碼,深度剖析 Object、String 實作細節與重寫規範。

Object.equals() 規約與預設實作

public boolean equals(Object obj) {
    return (this == obj); // 僅比較參考位址
}

五大數學特性:

  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

關鍵契約:若覆寫 equals(),必須覆寫 hashCode(),確保相等物件擁有相同雜湊碼。

String.equals() 實作邏輯

public boolean equals(Object anObject) {
    if (this == anObject) return true; // 同參考快速返回
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i]) return false; // 逐字元比較
                i++;
            }
            return true;
        }
    }
    return false;
}

兩階段比較:1. 參考相等 2. 內容逐字元比較。

String.hashCode() 計算演算法

public int hashCode() {
    int h = hash; // 快取
    if (h == 0 && value.length > 0) {
        char val[] = value;
        for (int i = 0; i < value.length; i++) {
            h = 31 * h + val[i]; // h = s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
        }
        hash = h;
    }
    return h;
}

採用 31 為質數乘數 (效能優化:31*i == (i<<5)-i),空字串 hashCode 為 0。

重寫規範與常見錯誤

場景正確做法錯誤示範
覆寫 equals()同時覆寫 hashCode(),使用相同欄位計算只覆寫 equals(),導致 HashMap 找不到相等物件
欄位選擇包含所有參與 equals 比較的欄位equals 比較 id+name,hashCode 只用 id
可變物件不可變欄位計算 hashCode,或確保放入集合後不修改List 作為 Key 後修改內容,導致找不到
效能考量常用欄位優先、避免昂貴運算、考慮快取每次計算 hashCode 都遍歷大型集合

最佳實務範本 (Objects 輔助類 Java 7+)

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    MyClass that = (MyClass) o;
    return Objects.equals(id, that.id) &&
           Objects.equals(name, that.name);
}

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

遵循契約、使用標準庫輔助、保持欄位一致性,是正確實作 equals/hashCode 的關鍵。

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