程式碼重用是 Java 最引人注目的特性之一,但若要成為革命性的語言,僅能複製並修改程式碼是遠遠不夠的。Java 提供了兩種核心重用機制——組合與繼承,並輔以 final 關鍵字對變更進行管控。本文將系統梳理這些機制的語法、初始化細節、記憶體清除策略,以及設計選型的判斷依據。
組合的本質是在新類別中持有現有類別的物件引用。類別中的基本型別欄位會自動初始化為零值,但物件引用預設為 null。初始化引用可在四個位置進行:
{ ... } 區塊,適用於多建構子共享的初始化邏輯。所有 Java 類別若未顯式指定父類別,皆隱式繼承 java.lang.Object。繼承語法為 class Child extends Parent {}。繼承不僅是程式碼重用,更表達了「子類別是一種父類別」的型別關係。
子類別建構子會自動呼叫父類別的無參數建構子;若需呼叫帶參數的父類建構子,必須在子類建構子首行使用 super(args) 顯式指定。
Java 的垃圾收集器(GC)僅管理記憶體回收,無法保證執行順序、執行時間,甚至可能永不執行。因此:
finalize() 進行非記憶體資源(檔案控制代碼、資料庫連線、網路通訊端等)的釋放。cleanup()、close() 或實作 AutoCloseable,由呼叫端在 try-with-resources 或 finally 區塊中明確調用。System.runFinalizersOnExit(true) 強制執行終結器,但此做法已過時且不建議使用。在物件導向設計中,組合是常態,繼承是特例。判斷依據極為簡單:
是否需要從子類別向上轉型為父類別?
若必須向上轉型(多型調用),則使用繼承;若無此需求,優先採用組合,避免濫用繼承造成的脆弱基礎類別問題。
protected 意為「對外私有,但對子類別與同一套件內的類別可見」。它保留了封裝性,同時開放給繼承體系與套件內協作者使用。
繼承支援「累積開發」:在不修改既有功能類別的前提下,透過擴充新增資料欄位、方法或覆寫既有方法,將潛在錯誤隔離在新程式碼中。一旦出錯,即知定為新增程式碼所致,大幅降低除錯成本。
繼承最關鍵的價值在於「向上轉型」——將子類別物件視為父類別型別處理。這使得演算法可針對父類別介面編程,並在執行期綁定具體子類別行為,實現多型。類別繼承圖慣以根類別置頂、向下擴展,故稱「向上」轉型。
final 使數值成為編譯期或執行期常數。final 鎖定引用指向的物件,但物件內部狀態仍可修改。final,防止在方法內改變參數引用指向。使用 final 修飾方法有兩大動機:
final 方法內聯,減少呼叫開銷(現代 JIT 編譯器已大幅弱化此優勢)。類別宣告為 final 表示不可被繼承。典型案例為 String、Integer 等不可變類別,確保其語意不被子類別破壞。
傳統語言(如 C++)在啟動階段一次性載入所有程式碼,易導致 static 欄位跨檔案初始化順序難題。Java 採用動態類別載入:
.class 檔案。此機制從根本上解決了跨類別 static 初始化的循環依賴問題。