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

為什麼重寫 equals 必須重寫 hashCode

     編輯:Java 相關知識

Java equals 與 hashCode 契約深度解析

核心規約

若兩個對象根據 equals() 判斷相等,則它們的 hashCode() 必須相等。
反之,hashCode() 相等的對象,equals() 不一定相等(哈希碰撞)。

違反契約的後果:HashSet/HashMap 失效

場景:學生學號去重

class Student {
    private int stuNo;
    private String name;
    // 建構子、getter 省略
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj instanceof Student) {
            return this.stuNo == ((Student) obj).stuNo;
        }
        return false;
    }
    // 忘記重寫 hashCode()!
}

public class Test {
    public static void main(String[] args) {
        Set<Student> set = new HashSet<>();
        set.add(new Student(123, "Tom"));
        set.add(new Student(456, "Jerry"));
        set.add(new Student(123, "Lily")); // 同學號,應去重
        
        for (Student s : set) {
            System.out.println(s.getStuNo() + " - " + s.getName());
        }
    }
}

輸出結果

123 - Lily
456 - Jerry
123 - Tom  // 重複學號未去重!

根因分析:HashMap 底層邏輯

  1. HashSet.add() 內部調用 HashMap.put()
  2. put() 計算 hash(key) 確定桶位置
  3. 遍歷鏈表比較:e.hash == hash && (e.key == key || key.equals(k))
  4. 關鍵點:先比 hashCode,不等則直接判定為不同對象,不再調用 equals

未重寫 hashCode 時,預設使用 Object.hashCode()(基於內存地址),導致邏輯相等的對象哈希值不同,落入不同桶位,equals 根本不被調用。

正確實作

@Override
public int hashCode() {
    return Integer.hashCode(stuNo); // 或 Objects.hash(stuNo)
}

@Override
public boolean equals(Object obj) {
    if (this == obj) return true;
    if (!(obj instanceof Student)) return false;
    Student other = (Student) obj;
    return this.stuNo == other.stuNo;
}

修正後輸出

456 - Jerry
123 - Tom  // 正確去重,保留首個

為什麼要先比 hashCode?

性能優化: equals 可能涉及複雜業務邏輯(多字段比較、遞歸比較),hashCode 比較極快(整數比較)。先過濾掉明顯不同的對象,大幅提升查找效率。

最佳實踐指南

  1. 必須成對重寫:重寫 equals 時必須重寫 hashCode
  2. 使用相同字段:兩個方法使用的字段集合必須一致
  3. 使用工具類: Objects.hash(field1, field2...) (Java 7+) 或 IDE 自動生成
  4. 不可變對象:參與 equals/hashCode 的字段應為 final 或不可變
  5. 不要在 hashCode 中包含集合/數組:除非深度計算,否則性能差且易變

常見誤區

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
誤區正確理解
hashCode 相等即 equals 相等哈希碰撞不可避免,必須再調用 equals 確認
只要不放入 HashSet/HashMap 就不用重寫未來代碼變更可能放入,最好養成習慣
返回常數如 42 即可雖合法但退化為鏈表,性能極差
用內存地址計算 hashCode違反契約,邏輯相等對象會有不同哈希