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

Java 重寫 equals 必須同步重寫 hashCode 的原因深度解析

     編輯:Java 相關知識

核心契約

Java 規範定義 equals 與 hashCode 的雙向契約:

  1. 一致性:若 a.equals(b) == true,則 a.hashCode() == b.hashCode() 必須成立。
  2. 非唯一性:hashCode 相等不代表 equals 相等(哈希碰撞)。

為什麼需要 hashCode?

哈希表(HashMap/HashSet)查找流程

  1. 計算 key 的 hashCode() 確定桶位置。
  2. 在該桶的鏈表/紅黑樹中遍歷,調用 equals() 比較。

若未重寫 hashCode,邏輯相等的對象可能落入不同桶,導致無法命中,破壞集合語義。

String 源碼示例

// equals 逐字符比較
public boolean equals(Object anObject) {
    if (this == anObject) return true;
    if (anObject instanceof String) {
        String another = (String) anObject;
        if (count != another.count) return false;
        char[] v1 = value, v2 = another.value;
        int i = offset, j = another.offset;
        while (count-- != 0) if (v1[i++] != v2[j++]) return false;
        return true;
    }
    return false;
}

// hashCode 多項式滾動哈希
public int hashCode() {
    int h = hash; // 緩存
    if (h == 0) {
        for (int i = 0; i < count; i++) {
            h = 31 * h + val[off++];
        }
        hash = h;
    }
    return h;
}

相同字符串必然產生相同哈希值,滿足契約。

實戰場景:Set 去重

class Student {
    String name; int age;
    // 重寫 equals 比較 name+age
    // 若不重寫 hashCode -> 繼承 Object.hashCode() (基於內存地址)
}

Set set = new HashSet<>();
set.add(new Student("張三", 20));
set.add(new Student("張三", 20)); // 邏輯相同,但 hashCode 不同
// 結果:Set 包含兩個元素!違反去重預期

最佳實踐模板

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

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

常見誤區

誤區後果
只重寫 equals,不重寫 hashCode哈希集合失效,邏輯相等對象被視為不同
hashCode 使用可變字段對象入集合後修改字段導致找不到(哈希值變化)
equals 比較非業務字段(如 ID)但 hashCode 用其他字段違反契約,集合行為不可預期

總結

hashCode 是性能優化的關鍵:將 O(n) 線性比較降為 O(1) 桶定位 + 少量 equals。重寫時必須使用相同的業務字段,確保「equals 相等 ⇒ hashCode 相等」。

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