首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

Java 物件實例化順序詳解:繼承鏈下的構造器執行流程與面試題破解

     編輯:程式設計疑難解答

Java 物件創建時,父類與子類的靜態塊、構造塊、構造器執行順序是經典面試必考點。本文透過一道具體選擇題,逐步演示完整初始化流程,建立清晰的心智模型。

面試題目

class X {
    Y b = new Y();           // ① 成員變量初始化
    X() { System.out.print("X"); } // ② 構造器
}
class Y {
    Y() { System.out.print("Y"); } // ③ 構造器
}
public class Z extends X {
    Y y = new Y();           // ④ 成員變量初始化
    Z() { System.out.print("Z"); } // ⑤ 構造器
    public static void main(String[] args) { new Z(); }
}
// 輸出選項: A) Z  B) YZ  C) XYZ  D) YXYZ

核心規則:Java 物件初始化「七步曲」

  1. 父類靜態成員/靜態塊 (按聲明順序,僅類首次加載執行一次)。
  2. 子類靜態成員/靜態塊 (同上)。
  3. 父類非靜態成員變量初始化 / 實例初始化塊 (按聲明順序)。
  4. 父類構造器 執行。
  5. 子類非靜態成員變量初始化 / 實例初始化塊 (按聲明順序)。
  6. 子類構造器 執行。
  7. 注意:子類構造器**隱式/顯式 `super()`** 必須為第一句,觸發父類構造器鏈,故父類初始化 (3-4) 總在子類初始化 (5-6) 之前完成。

逐步追蹤 `new Z()`

步驟動作輸出說明
1加載類 `X`、`Y`、`Z` (無靜態成員/塊,無輸出)-類加載階段
2調用 `Z()` 構造器 → 隱式 `super()` → 調用 `X()`-構造器鏈啟動
3執行 `X` 的非靜態成員初始化:`Y b = new Y()`Y① 號位置,調用 `Y()` 構造器
4執行 `X()` 構造器體:`System.out.print("X")`X② 號位置
5返回 `Z()`,執行 `Z` 的非靜態成員初始化:`Y y = new Y()`Y④ 號位置,再次調用 `Y()`
6執行 `Z()` 構造器體:`System.out.print("Z")`Z⑤ 號位置

最終輸出:`YXYZ` (選項 D)

關鍵陷阱解析

  • 誤區 1:以為先跑完父類構造器再初始化子類成員。**事實**:父類構造器執行**前**,父類成員已初始化完畢;父類構造器執行**後**,才輪到子類成員初始化。
  • 誤區 2:忽略成員變量 `new Y()` 是在構造器**之前**執行的隱式初始化動作。
  • 誤區 3:以為 `Y` 只會 `new` 一次。**事實**:`X` 和 `Z` 各自持有 `Y` 實例,共創建兩個 `Y` 物件,故輸出兩次 `Y`。

驗證代碼 (可直接運行)

class X { Y b = new Y(); X() { System.out.print("X"); } }
class Y { Y() { System.out.print("Y"); } }
public class Z extends X { Y y = new Y(); Z() { System.out.print("Z"); } 
    public static void main(String[] args) { new Z(); } }
// 控制台輸出: YXYZ

總結

**口訣:靜態父→靜態子→父成員→父構造→子成員→子構造。** 牢記「成員初始化先於本類構造器,父類鏈優於子類」的核心原則,任何複雜繼承鏈初始化順序題皆可迎刃而解。

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