本文為《Effective Java》第 2 章讀書筆記,專講 java.lang.Object 非 final 方法的正確覆寫規範,是 Java 開發者必修的核心功夫。
五大約定:
x.equals(x) == truex.equals(y) == y.equals(x)x.equals(y) && y.equals(z) → x.equals(z)x.equals(null) == false易錯點: 對稱性與傳遞性在繼承中極易破壞。無法在擴展可實例化類並新增屬性的同時保持 equals 約定(除非放寬約定或使用組合)。
高質量 equals 處方:
== 檢查同一引用。instanceof 檢查類型(或 getClass() == obj.getClass() 嚴格模式)。Object,勿改為具體類(違反覆寫簽名)。替代方案: 組合取代繼承,避開 equals 陷阱。
否則無法在 HashMap/HashSet 等基於雜湊的集合中正常工作。理想雜湊函數將不等對象均勻分佈。
標準實現模板(Josh Bloch 配方):
@Override public int hashCode() {
int result = 17; // 非零常數
result = 31 * result + (boolField ? 1 : 0);
result = 31 * result + intField;
result = 31 * result + (int)(longField ^ (longField >>> 32));
result = 31 * result + Float.floatToIntBits(floatField);
long tmp = Double.doubleToLongBits(doubleField);
result = 31 * result + (int)(tmp ^ (tmp >>> 32));
result = 31 * result + (objField == null ? 0 : objField.hashCode());
result = 31 * result + Arrays.hashCode(arrayField);
return result;
}
31*i == (i<<5)-i)。提供「自我描述」能力,便於除錯、日誌、UI 顯示。格式建議:ClassName[field1=value1, field2=value2]。若類含大量數據或敏感信息,可僅返回摘要。
clone() 是另一構造器,實現深拷貝極其複雜且危險:
Cloneable(標記介面)。super.clone() 獲取淺拷貝。final 欄位無法修改的限制。更好替代:拷貝構造器 / 拷貝工廠方法
public Yum(Yum source) { // 拷貝構造器
this.field = source.field; // 不可變直接賦值
this.mutableList = new ArrayList<>(source.mutableList); // 可變深拷貝
}
public static Yum newInstance(Yum source) { return new Yum(source); } // 工廠
優點:無拋出受檢異常、無需實現標記介面、類型安全、可轉換實現類型。
若類有自然順序(如數值、字串、日期),實現 Comparable<T>,滿足與 equals 一致的自反、對稱、傳遞、一致約定。配合 Collections.sort()、TreeSet/TreeMap、Arrays.sort() 等標準算法無縫協作。
正確覆寫 Object 方法是專業 Java 開發者的分水嶺。遵循約定、使用標準模板、偏向拷貝構造器而非 clone、實現 Comparable 以賦能標準庫,能寫出健壯、高效、可維護的類。