首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Object 類核心方法深度解析:toString、equals、hashCode、getClass、clone、finalize

     編輯:Java 相關知識

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/waitpublic final❌監視器鎖協作,需在 synchronized 區塊調用執行緒等待/通知機制

核心方法深度解析

1. 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()。

2. equals() 與 hashCode():不可分割的雙子星

核心契約 (JLS §15.21.3):

  1. 自反性:x.equals(x) == true
  2. 對稱性:x.equals(y) ⇔ y.equals(x)
  3. 傳遞性:x.equals(y) && y.equals(z) ⇒ x.equals(z)
  4. 一致性:多次調用結果不變 (除非修改比較依據欄位)
  5. 非空性: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

3. getClass():運行時類型標識

  • final,不可覆寫,安全獲取真實類別。
  • obj.getClass().getName() 獲取全限定名;getSimpleName() 獲取簡單名。
  • 配合 instanceof:if (obj instanceof User u) (Java 16+ 模式匹配) 更優雅。
  • 序列化/反射/動態代理核心依賴。

4. clone():淺拷貝的陷阱

// 僅示範標準模式,現代 Java 建議用「拷貝建構子」或「靜態工廠方法」替代
@Override
protected User clone() throws CloneNotSupportedException {
    User cloned = (User) super.clone(); // 淺拷貝:基本類型複製、引用共享
    // 深拷貝需手動處理可變引用欄位
    cloned.mutableField = new ArrayList<>(this.mutableField);
    return cloned;
}

為何不推薦:

  • 需實作 Cloneable (標記介面),否則拋 CloneNotSupportedException。
  • 預設淺拷貝,可變物件共享引用極易導致 Bug。
  • 建構子/工廠方法語義更清晰、類型安全、可拋受檢異常、支援 final 欄位。

5. finalize():已棄用的歷史包袱

  • Java 9 標記 @Deprecated(since="9", forRemoval=true),Java 18 移除。
  • 問題:執行時間不確定、可能復活物件、拖慢 GC、異常吞沒、無序執行。
  • 替代:try-with-resources (自動資源管理)、Cleaner (Java 9+)、PhantomReference (精確生命週期)。

實戰檢查清單

  1. 所有實體類別 (Entity/DTO/VO) **必須** 覆寫 toString()。
  2. 作為 HashMap Key 或 HashSet 元素的類別,**必須成對** 覆寫 equals() / hashCode()。
  3. 使用 IDE (Alt+Insert) 或 Lombok @Data/@EqualsAndHashCode 自動生成,再人工審核業務鍵選擇。
  4. 不可變類別 (所有欄位 final) 的 hashCode() 可緩存計算結果。
  5. 禁止在 equals() 中進行 I/O、資料庫查詢、複雜計算。

Object 這 7 個可覆寫方法,看似簡單,實則蘊含豐富的語義契約與工程智慧。嚴格遵守契約,才能讓集合框架、序列化、緩存、日誌等基礎設施正確高效運作。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved