java.lang.Object 是所有 Java 類別的終極父類別,定義了 11 個方法,其中 7 個為非 final 可覆寫。掌握這些方法的契約與最佳實踐,是編寫正確、高效、可維護 Java 代碼的基石。
| 方法 | 修飾符 | 可覆寫 | 核心契約 | 典型用途 |
|---|---|---|---|---|
toString() | public | ✅ | 返回物件簡潔、可讀的字串表達 | 除錯、日誌、字串拼接 |
equals(Object) | public | ✅ | 自反性、對稱性、傳遞性、一致性、非空性 | 集合查找、去重、業務鍵比較 |
hashCode() | public | ✅ | equals 為 true ⇒ hashCode 必相等 | HashMap/HashSet 鍵、分桶索引 |
getClass() | public final | ❌ | 返回運行時類別 Class<?> | 反射、類型檢查、序列化 |
clone() | protected | ✅ | 淺拷貝;實作 Cloneable 否則拋異常 | 可變物件防禦性拷貝 |
finalize() | protected | ✅ (Deprecated) | GC 前調用;不可靠、已棄用 | 歷史資源清理 (現用 try-with-resources) |
notify/notifyAll/wait | public final | ❌ | 監視器鎖協作,需在 synchronized 區塊調用 | 執行緒等待/通知機制 |
toString():物件的「身分證」預設實作:getClass().getName() + "@" + Integer.toHexString(hashCode()) (如 com.example.User@1f89ab83) —— 幾乎無業務價值。
最佳實踐:
@Override
public String toString() {
return "User{id=%d, name='%s', email='%s'}".formatted(id, name, email);
// Java 12+ 可用 String.formatted,舊版用 String.format 或 StringBuilder
}
System.out.println(list) 會自動調用元素 toString()。equals() 與 hashCode():不可分割的雙子星核心契約 (JLS §15.21.3):
x.equals(x) == truex.equals(y) ⇔ y.equals(x)x.equals(y) && y.equals(z) ⇒ x.equals(z)x.equals(null) == false標準實作模板 (Java 7+ Objects 輔助):
@Override
public boolean equals(Object o) {
if (this == o) return true; // 同一引用快速路徑
if (o == null || getClass() != o.getClass()) return false; // 類型檢查
User user = (User) o;
return id == user.id && // 基本類型直接比較
Objects.equals(name, user.name) && // 物件類型用 Objects.equals (null 安全)
Objects.equals(email, user.email);
}
@Override
public int hashCode() {
return Objects.hash(id, name, email); // 自動處理 null、組合雜湊
}
| 錯誤 | 後果 | 修正 |
|---|---|---|
| 只覆寫 equals 不覆寫 hashCode | 放入 HashMap/HashSet 找不到、重複、記憶體洩漏 | 必須成對覆寫 |
| equals 用 instanceof 而非 getClass | 破壞對稱性 (子類別可等於父類別,反向不成立) | 嚴格用 getClass() 比較,或精心設計 instanceof 方案 |
| hashCode 包含可變欄位 | 物件修改後在 HashMap 中找不到 (桶位改變) | 僅使用不可變欄位計算 hashCode |
| equals 參數型別寫成具體類別 | 不是覆寫而是重載,@Override 會報錯 | 參數必須是 Object |
getClass():運行時類型標識obj.getClass().getName() 獲取全限定名;getSimpleName() 獲取簡單名。instanceof:if (obj instanceof User u) (Java 16+ 模式匹配) 更優雅。clone():淺拷貝的陷阱// 僅示範標準模式,現代 Java 建議用「拷貝建構子」或「靜態工廠方法」替代
@Override
protected User clone() throws CloneNotSupportedException {
User cloned = (User) super.clone(); // 淺拷貝:基本類型複製、引用共享
// 深拷貝需手動處理可變引用欄位
cloned.mutableField = new ArrayList<>(this.mutableField);
return cloned;
}
為何不推薦:
Cloneable (標記介面),否則拋 CloneNotSupportedException。finalize():已棄用的歷史包袱@Deprecated(since="9", forRemoval=true),Java 18 移除。try-with-resources (自動資源管理)、Cleaner (Java 9+)、PhantomReference (精確生命週期)。toString()。HashMap Key 或 HashSet 元素的類別,**必須成對** 覆寫 equals() / hashCode()。@Data/@EqualsAndHashCode 自動生成,再人工審核業務鍵選擇。hashCode() 可緩存計算結果。equals() 中進行 I/O、資料庫查詢、複雜計算。Object 這 7 個可覆寫方法,看似簡單,實則蘊含豐富的語義契約與工程智慧。嚴格遵守契約,才能讓集合框架、序列化、緩存、日誌等基礎設施正確高效運作。