首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java equals() 與 == 核心區別:String 物件比較、HashMap 鍵值正確性與最佳實踐

     編輯:程式設計綜合問答

核心結論:equals() 比較「內容」,== 比較「記憶體位址」

String a = new String("hello");
String b = new String("hello");
System.out.println(a == b);        // false (不同物件,不同位址)
System.out.println(a.equals(b));   // true  (內容相同)

為什麼 HashMap 鍵值類必須正確覆寫 equals() 與 hashCode()?

HashMap 依賴 hashCode() 定位桶位,再用 equals() 比較鍵值是否相同。若兩物件「邏輯相等」但 hashCode() 不同,或 equals() 判斷錯誤,會導致:

  • 無法取得已放入的值:map.get(key) 回傳 null。
  • 重複鍵值:邏輯相同的鍵被視為不同,佔用多個桶位。
  • 記憶體洩漏風險:無法移除舊條目。

程式碼分析:Student 類別的 equals() 實作

public boolean equals(Object obj) {
    if(!(obj instanceof Student)) throw new ClassCastException("類型不匹配"); // 問題 1
    Student s = (Student)obj;
    return this.name.equals(s.name) && this.age == s.age; // 正確
    // return this.name == s.name && this.age == s.age;  // 錯誤!
}

錯誤 1:拋出 ClassCastException 違反 equals() 契約

  • equals() 契約要求:對任何非 null 參考 x.equals(y) 應回傳 false 而非拋出異常 (除非 y 為 null)。
  • 正確寫法:if (!(obj instanceof Student)) return false;

錯誤 2:使用 == 比較 String

  • this.name == s.name 比較**引用位址**。只有字串常量池或 intern() 後的字串才可能相同引用。
  • new String("abc") == new String("abc") 為 false,但 .equals() 為 true。
  • **永遠使用 .equals() 比較字串內容**。

標準 equals() 實作模板 (Java 7+ Objects 工具類)

import java.util.Objects;

public class Student implements Comparable<Student> {
    private String name;
    private int age;

    // 建構子、getter、setter、compareTo、toString 省略

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;                    // 同一引用快速返回
        if (o == null || getClass() != o.getClass()) return false; // 型別檢查
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name); // null-safe 比較
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age); // 自動處理 null、質數乘法組合
    }
}

hashCode() 契約與實作要點

  1. 一致性:a.equals(b) == true → a.hashCode() == b.hashCode() (反之不必然)。
  2. 穩定性:物件生命週期內未修改 equals 依賴欄位時,hashCode 必須穩定。
  3. 分散性:不同物件 hashCode 應盡量分散,減少碰撞提升 HashMap 效能。
  4. 欄位選擇:僅包含 equals() 使用的欄位,排除可變欄位。

常見陷阱對照表

場景錯誤寫法正確寫法後果
String 比較s1 == s2s1.equals(s2) 或 Objects.equals(s1,s2)邏輯相等物件判定為不等
equals 型別檢查throw new ClassCastExceptionreturn false違反契約、集合操作拋異常
可變欄位參與 hashCode含 List、Date 等可變物件僅用不可變/邏輯鍵欄位修改欄位後無法在 HashMap 找到
未覆寫 hashCode只覆寫 equals必須同時覆寫HashMap/HashSet 失效
對稱性違反A.equals(B) != B.equals(A)使用 getClass() 檢查而非 instanceof (若不可變)集合行為不可預期

IDE 自動生成與庫支援

  • IntelliJ IDEA / Eclipse:Alt+Insert → equals() and hashCode() 依欄位自動生成標準實作。
  • Lombok:@EqualsAndHashCode 註解編譯期自動生成,支援 callSuper、onlyExplicitlyIncluded 等精細控制。
  • Java 14+ Record:record Student(String name, int age) {} 自動獲得正確 equals/hashCode/toString。

總結

**String 比較內容必須用 .equals(),== 僅比較引用。** 覆寫 equals() 時:遵守契約 (自反、對稱、傳遞、一致、非 null 回 false)、使用 Objects.equals 處理 null、**必須同步覆寫 hashCode()**。善用 IDE 自動生成、Lombok 或 Record 避免手寫錯誤。這是 Java 集合框架正確運作的基石,亦是面試必考核心。

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