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

Java 建構子調用機制深度解析

     編輯:Java 相關知識

理解 Java 物件初始化順序與建構子鏈結是撰寫正確繼承體系的基石。本文梳理從類載入到實例化的完整流程,並以兩個對比範例說明 super() 顯式調用與預設調用的差異。

初始化順序總覽

  1. 父類靜態變數/靜態區塊(按宣告順序)
  2. 子類靜態變數/靜態區塊(按宣告順序)
  3. 父類非靜態變數/非靜態區塊(按宣告順序)
  4. 父類建構子
  5. 子類非靜態變數/非靜態區塊(按宣告順序)
  6. 子類建構子

核心規則

  • 子類建構子第一行必須調用父類建構子(super(...) 或 this(...)),否則編譯器自動插入 super()。
  • 若父類無無參建構子,子類必須顯式調用帶參數的 super(...),否則編譯錯誤。
  • super() 僅能出現在建構子第一行,不能在方法或區塊中使用。

範例對比

Example 1:子類建構子顯式調用 super(x, y)

class Father {
    int x = 0, y = 0;
    Father() { System.out.println("Father 無參建構子"); }
    Father(int x, int y) { this.x = x; this.y = y; }
    void print() { System.out.println("x=" + x + "; y=" + y); }
}

class Son extends Father {
    Son() { System.out.println("Son 無參建構子"); }
    Son(int x, int y) { super(x, y); } // 顯式調用父類帶參建構子
    void print() { super.print(); System.out.println("I am Son"); }
}

public class Example1 {
    public static void main(String[] args) {
        Son s1 = new Son();      // 輸出: Father無參 -> Son無參
        s1.print();              // x=0; y=0 -> I am Son
        Son s2 = new Son(10,20); // 輸出: Father(10,20) -> Son(10,20)
        s2.print();              // x=10; y=20 -> I am Son
    }
}

Example 2:子類建構子未顯式調用 super(x, y)

class Son extends Father {
    Son(int x, int y) { System.out.println("s213"); } // 無 super(x,y),預設調用 super()
    void print() { System.out.println("I am Son"); }   // 未調用 super.print()
}

public class Example2 {
    public static void main(String[] args) {
        Son s1 = new Son();       // Father無參 -> Son無參
        s1.print();               // I am Son
        Son s2 = new Son(10,20);  // Father無參 -> s213  (x,y 仍為 0)
        s2.print();               // I am Son
    }
}

關鍵差異: Example 1 中 Son(int,int) 透過 super(x,y) 初始化父類欄位,Example 2 則只執行父類無參建構子,導致 x,y 保持預設值 0。這證明:子類建構子預設調用父類無參建構子;若需傳參初始化父類狀態,必須顯式寫 super(...)。

設計建議

  • 盡量讓父類提供無參建構子,或在所有子類建構子中統一顯式調用帶參 super(...)。
  • 避免在建構子中調用可被覆寫的方法(見《Effective Java》Item 19),防止子類尚未初始化完成時就被回呼。
  • 優先考慮組合(Composition)而非繼承,除非確定存在「is-a」關係且需要多型。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved