String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false (不同物件,不同位址)
System.out.println(a.equals(b)); // true (內容相同)
HashMap 依賴 hashCode() 定位桶位,再用 equals() 比較鍵值是否相同。若兩物件「邏輯相等」但 hashCode() 不同,或 equals() 判斷錯誤,會導致:
map.get(key) 回傳 null。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; // 錯誤!
}
equals() 契約要求:對任何非 null 參考 x.equals(y) 應回傳 false 而非拋出異常 (除非 y 為 null)。if (!(obj instanceof Student)) return false;== 比較 Stringthis.name == s.name 比較**引用位址**。只有字串常量池或 intern() 後的字串才可能相同引用。new String("abc") == new String("abc") 為 false,但 .equals() 為 true。.equals() 比較字串內容**。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、質數乘法組合
}
}
a.equals(b) == true → a.hashCode() == b.hashCode() (反之不必然)。equals() 使用的欄位,排除可變欄位。| 場景 | 錯誤寫法 | 正確寫法 | 後果 |
|---|---|---|---|
| String 比較 | s1 == s2 | s1.equals(s2) 或 Objects.equals(s1,s2) | 邏輯相等物件判定為不等 |
| equals 型別檢查 | throw new ClassCastException | return false | 違反契約、集合操作拋異常 |
| 可變欄位參與 hashCode | 含 List、Date 等可變物件 | 僅用不可變/邏輯鍵欄位 | 修改欄位後無法在 HashMap 找到 |
| 未覆寫 hashCode | 只覆寫 equals | 必須同時覆寫 | HashMap/HashSet 失效 |
| 對稱性違反 | A.equals(B) != B.equals(A) | 使用 getClass() 檢查而非 instanceof (若不可變) | 集合行為不可預期 |
Alt+Insert → equals() and hashCode() 依欄位自動生成標準實作。@EqualsAndHashCode 註解編譯期自動生成,支援 callSuper、onlyExplicitlyIncluded 等精細控制。record Student(String name, int age) {} 自動獲得正確 equals/hashCode/toString。**String 比較內容必須用 .equals(),== 僅比較引用。** 覆寫 equals() 時:遵守契約 (自反、對稱、傳遞、一致、非 null 回 false)、使用 Objects.equals 處理 null、**必須同步覆寫 hashCode()**。善用 IDE 自動生成、Lombok 或 Record 避免手寫錯誤。這是 Java 集合框架正確運作的基石,亦是面試必考核心。