Object.equals(Object) 用於判斷兩個物件是否「邏輯相等」。預設實作比較參考位址 (this == obj),子類別需覆寫以實現值語意。
x.equals(x) == truex.equals(y) == y.equals(x)x.equals(y) && y.equals(z) → x.equals(z)x.equals(null) == false違反規約會導致HashMap、HashSet、ArrayList.contains()等集合行為錯誤。
if (!(obj instanceof MyClass)) return false;
支援子類別多態比較;若需嚴格同類別可用 getClass() != obj.getClass()。
MyClass other = (MyClass) obj;
return this.id == other.id
&& Objects.equals(this.name, other.name)
&& Double.compare(this.score, other.score) == 0;
== (float/double 用 Float.compare/Double.compare 處理 NaN)。Objects.equals(a, b) (Null-safe)。Arrays.equals 或 Arrays.deepEquals。@Override
public int hashCode() {
return Objects.hash(id, name, score);
}
鐵律:a.equals(b) → a.hashCode() == b.hashCode()。反之不必然。
編譯器會檢查簽名是否正確覆寫,防止拼字錯誤變成多載。
如 id 為主鍵,優先比較 id,不相等直接返回,避免昂貴字串比較。
public final class User {
private final long id;
private final String name;
private final double score;
public User(long id, String name, double score) {
this.id = id;
this.name = name;
this.score = score;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof User)) return false;
User other = (User) obj;
return id == other.id
&& Objects.equals(name, other.name)
&& Double.compare(score, other.score) == 0;
}
@Override
public int hashCode() {
return Objects.hash(id, name, score);
}
}
| 錯誤 | 後果 |
|---|---|
| 只覆寫 equals 不覆寫 hashCode | 放入 HashMap/HashSet 找不到、重複 |
| 參數型別寫成 MyClass 而非 Object | 變成多載,集合仍呼叫 Object.equals |
| 使用 getClass() 破壞對稱性 | 子類別實例與父類別實例比較失效 |
| 比較可變欄位 | 物件放入 Set 後修改欄位導致找不到 |
| float/double 直接 == 比較 | NaN、-0.0 語意錯誤 |
@EqualsAndHashCode 註解自動實作。