equals() 必須滿足等價關係五大公理:
x.equals(x) == truex.equals(y) == y.equals(x)x.equals(y) && y.equals(z) → x.equals(z)x.equals(null) == false違反契約後果:導致 HashSet、HashMap、ArrayList.contains() 等集合行為錯誤 (如無法找到已放入的元素、重複元素)。
public boolean equals(Object obj) {
return (this == obj); // 比較記憶體位址 (身分相等)
}
所有類別預設繼承此行為,**值物件 (Value Object) 必須覆寫** 比較內容。
@Override
public boolean equals(Object obj) {
if (this == obj) return true; // 同一物件快速返回
if (obj == null || getClass() != obj.getClass()) return null; // 型別檢查
MyClass other = (MyClass) obj;
return Objects.equals(field1, other.field1) &&
Objects.equals(field2, other.field2) &&
primitiveField == other.primitiveField;
}
| 策略 | 行為 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|---|
| getClass() | 嚴格型別相等 | 滿足對稱性、傳遞性;簡單安全 | 子類別無法與父類別實例相等 | 預設首選、final 類別、值物件、不可變物件 |
| instanceof | 允許子類別比較 | 多型友善 | 極易違反對稱性/傳遞性 (見下例) | 極少數需跨類別層級比較的框架代碼 (如 JPA 實體) |
class Person {
String name;
// 使用 instanceof
public boolean equals(Object o) {
if (o instanceof Person) return name.equals(((Person)o).name);
return false;
}
}
class Employee extends Person {
int id;
// 覆寫加入 id 比較
public boolean equals(Object o) {
if (o instanceof Employee) return super.equals(o) && id == ((Employee)o).id;
return false;
}
}
Person p = new Person("John");
Employee e1 = new Employee("John", 1);
Employee e2 = new Employee("John", 2);
p.equals(e1); // true (Person 用 instanceof 比較 name)
p.equals(e2); // true (Person 用 instanceof 比較 name)
e1.equals(e2); // false (Employee 比較 id)
// 違反傳遞性:p=e1 且 p=e2 但 e1!=e2
結論:除非極度確定需求,**永遠使用 getClass()** 或 obj.getClass() == this.getClass()。
@Override
public int hashCode() {
return Objects.hash(field1, field2, primitiveField);
}
鐵律:a.equals(b) → a.hashCode() == b.hashCode()。違反會導致 HashMap/HashSet 失效。
| 類型 | 比較方式 |
|---|---|
| 基本型別 (int, long 等) | == |
| float | Float.compare(f1, f2) == 0 或 Float.floatToIntBits(f1) == Float.floatToIntBits(f2) |
| double | Double.compare(d1, d2) == 0 或 Double.doubleToLongBits(d1) == Double.doubleToLongBits(d2) |
| 物件參考 | Objects.equals(o1, o2) (內建 null 安全) |
| 陣列 | Arrays.equals(arr1, arr2) / Arrays.deepEquals |
| 列舉 | == 或 equals() (單例保證) |