Java 類加載與對象創建的初始化順序是面試高頻考點,也是理解框架底層 (Spring Bean 初始化、單例模式) 的基石。本文通過編譯器視角還原字節碼層面的執行流程,提供標準化順序模型與實戰驗證代碼。
核心原則:按源碼**從上到下、從父到子**順序,字段聲明賦值與靜態塊**交織執行**,而非分階段。
// 源碼
public class Person {
public static String name = "張三";
public static int age;
static { age = 20; System.out.println("靜態塊1"); }
public static String address;
static { address = "北京"; age = 34; }
}
// 編譯器生成的 邏輯等效代碼
public class Person {
public static String name;
public static int age;
public static String address;
static {
name = "張三"; // 字段聲明賦值
age = 20; // 靜態塊1
System.out.println("靜態塊1");
address = "北京"; // 靜態塊2
age = 34;
}
}
new 關鍵字、反射 Constructor.newInstance()、反序列化、clone()
// 源碼
public class Person {
{ name = "李四"; age = 56; System.out.println("實例塊"); address = "上海"; }
public String name = "張三";
public int age = 29;
public String address = "北京";
public Person() { name = "趙六"; age = 23; address = "上海市"; }
}
// 編譯器生成 等效代碼
public Person() {
// 1. 隱式 super() 已完成父類初始化
name = "李四"; // 實例塊 (按源碼順序)
age = 56;
System.out.println("實例塊");
address = "上海";
name = "張三"; // 字段聲明賦值 (按源碼順序)
age = 29;
address = "北京";
name = "趙六"; // 構造器體
age = 23;
address = "上海市";
}
super() 觸發父類完整初始化
class Parent {
static { System.out.println("1. Parent static block"); }
static String pStatic = init("2. Parent static field");
{ System.out.println("3. Parent instance block"); }
String pInst = init("4. Parent instance field");
Parent() { System.out.println("5. Parent constructor"); }
static String init(String s) { System.out.println(s); return s; }
}
class Child extends Parent {
static { System.out.println("6. Child static block"); }
static String cStatic = init("7. Child static field");
{ System.out.println("8. Child instance block"); }
String cInst = init("9. Child instance field");
Child() { System.out.println("10. Child constructor"); }
static String init(String s) { System.out.println(s); return s; }
}
public class InitOrderDemo {
public static void main(String[] args) {
System.out.println("=== new Child() ===");
new Child();
}
}
/* 輸出順序:
1. Parent static block
2. Parent static field
6. Child static block
7. Child static field
3. Parent instance block
4. Parent instance field
5. Parent constructor
8. Child instance block
9. Child instance field
10. Child constructor
*/
static final int CONST = 100; // 編譯期常量,不觸發類初始化
static final String STR = "hello"; // 同上
static final Object OBJ = new Object(); // 非常量,觸發初始化
class A { static int x = B.y + 1; }
class B { static int y = A.x + 1; }
// 首次訪問 A.x → 初始化 A → 需 B.y → 初始化 B → 需 A.x (正在初始化,默認值 0) → y=1 → x=2
class Base {
Base() { init(); } // 危險!
void init() { System.out.println("Base"); }
}
class Derived extends Base {
String field = "init";
@Override void init() { System.out.println(field); } // field 尚未初始化 → null
}
new Derived(); // 輸出 null,而非 "init"
線程安全 (內部鎖)static final Instance INSTANCE = new Instance(); (飽漢式線程安全)| 階段 | 順序 | 關鍵字 |
|---|---|---|
| 類加載 | 1. 父類靜態字段/塊 (源碼順) | static |
| 2. 子類靜態字段/塊 (源碼順) | static | |
| 對象創建 | 3. 父類實例字段/塊 (源碼順) | {} |
| 4. 父類構造器體 | constructor | |
| 5. 子類實例字段/塊 (源碼順) | {} | |
| 6. 子類構造器體 | constructor |
口訣:靜態先於實例、父類先於子類、字段塊按源碼序、構造器最後跑。