o.equals(o) == trueo.equals(o1) → o1.equals(o)o.equals(o1) ∧ o.equals(o2) → o1.equals(o2)o.equals(null) == falseObject 預設實現為參考比較(==),子類若需值比較必須覆寫。
JDK FieldPosition.equals 使用 instanceof 檢查:
if (!(obj instanceof FieldPosition)) return false;
測試代碼:
FieldPosition fp = new FieldPosition(10);
FieldPosition fp1 = new MyTest(10); // 子類
fp.equals(fp1) // true
fp1.equals(fp) // false ← 對稱性失效!
原因:子類 instanceof 父類為 true,父類 equals 通過;但子類 equals 要求 instanceof MyTest,父類實例失敗。
final 類別:可安全使用 instanceof(無子類)。final 類別:必須使用 obj.getClass() == this.getClass() 或 getClass() == Xxx.class(若不希望子類複用 equals)。if (this == obj) return true;public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
MyClass other = (MyClass) obj;
return Objects.equals(field1, other.field1)
&& field2 == other.field2
&& Objects.equals(field3, other.field3);
}
父類實現可用反射遍歷 getDeclaredFields() 自動比較所有欄位,確保子類不覆寫也能正確工作。
規約:a.equals(b) → a.hashCode() == b.hashCode()。
反例:PhoneNumber 覆寫 equals 但未覆寫 hashCode,導致 HashMap 以相等物件為鍵無法查找。
Map m = new HashMap();
PhoneNumber pn = new PhoneNumber(123, 38942, 230);
m.put(pn, "value");
m.get(new PhoneNumber(123, 38942, 230)); // 返回 null!
務必同步覆寫 hashCode,通常採用 Objects.hash(fields...) 或經典質數乘加算法。