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

Java 類加載與初始化順序:靜態塊、實例塊、構造器詳解

     編輯:程式設計綜合問答

問題代碼

public class A {
    private List list = new ArrayList(); // 實例字段初始化
    
    public static void main(String[] args) {
        A a = new A();
    }
}

生命周期階段

  1. 編譯:`javac A.java` → `A.class`(開發期,非運行期)
  2. 加載:類加載器讀取 `.class` 字節碼,生成 `java.lang.Class` 對象(JVM 啟動或首次主動使用時)
  3. 鏈接:驗證、準備(靜態字段賦默認值)、解析
  4. 初始化:執行 ``(靜態塊、靜態字段賦值)
  5. 實例化:`new A()` → 執行 ``(實例字段初始化、實例塊、構造器)

問題回答

Q1: 類何時編譯/加載?

  • 編譯:開發期手動或 IDE 自動
  • 加載:JVM 啟動加載入口類,或首次主動使用(new、訪問靜態字段/方法、反射、子類初始化)

Q2: `list` 對象何時創建?

實例化時(`new A()` 時),而非加載時。屬於實例字段初始化,在構造器之前執行。

Q3: 靜態塊執行時機?

類初始化階段,在 `main` 執行前、任何靜態成員訪問前、實例化前。只執行一次。

完整執行順序演示

public class OrderDemo {
    // 1. 靜態字段初始化
    static String sField = initStaticField();
    static { System.out.println("2. 靜態塊"); }
    
    // 3. 實例字段初始化
    String iField = initInstanceField();
    { System.out.println("4. 實例塊"); }
    
    // 5. 構造器
    public OrderDemo() { System.out.println("5. 構造器"); }
    
    public static void main(String[] args) {
        System.out.println("6. main 開始");
        new OrderDemo();
        System.out.println("7. main 結束");
    }
    
    static String initStaticField() { System.out.println("1. 靜態字段"); return ""; }
    String initInstanceField() { System.out.println("3. 實例字段"); return ""; }
}

/* 輸出順序:
1. 靜態字段
2. 靜態塊
6. main 開始
3. 實例字段
4. 實例塊
5. 構造器
7. main 結束
*/

父子類初始化順序

父類靜態字段 → 父類靜態塊 → 子類靜態字段 → 子類靜態塊
→ 父類實例字段 → 父類實例塊 → 父類構造器
→ 子類實例字段 → 子類實例塊 → 子類構造器

觸發類初始化的「主動使用」

  • `new` 實例化
  • 讀/寫非 final靜態字段
  • 調用靜態方法
  • 反射 `Class.forName` / `ClassLoader.loadClass`
  • 初始化子類(觸發父類初始化)
  • JVM 啟動主類

被動使用不觸發初始化:訪問父類靜態字段(子類不初始化)、數組創建、訪問 `final static` 常量(編譯期常量池)。

總結

  • 靜態成員(字段/塊):類加載初始化階段,一次,最早
  • 實例成員(字段/塊/構造器):每次 new 實例化,順序:字段→塊→構造器
  • `main` 方法屬於類初始化後執行
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved