Java 對象創建過程涉及父類構造、靜態/非靜態字段初始化、初始化塊、構造方法等多個階段。理解準確的初始化順序對於避免難以排查的 Bug、設計合理的繼承體系至關重要。本文通過一個經典驗證案例,詳細拆解對象初始化的完整鏈路。
public class Derive extends Base {
private Member m1 = new Member("Member 1");
{
System.out.println("Initial Block()");
}
public Derive() {
System.out.println("Derive()");
}
private Member m2 = new Member("Member 2");
private int i = getInt();
private int getInt() {
System.out.println("getInt()");
return 2;
}
public static void main(String[] args) {
new Derive();
}
}
class Base {
public Base() {
System.out.println("Base()");
}
}
class Member {
public Member(String m) {
System.out.println("Member() " + m);
}
}
Base()
Member() Member 1
Initial Block()
Member() Member 2
getInt()
Derive()
JVM 規定:子類構造方法第一行隱式或顯式調用 super()。因此 Base() 最先輸出。若父類無無參構造,子類必須顯式調用帶參 super(...)。
父類構造完成後,進入子類初始化階段:
new Member("Member 1") → 輸出 "Member() Member 1"{ System.out.println("Initial Block()"); } → 輸出 "Initial Block()"new Member("Member 2") → 輸出 "Member() Member 2"getInt() → 輸出 "getInt()"關鍵點:字段初始化和初始化塊的執行順序完全取決於它們在類中聲明的順序,交替執行。
所有字段初始化完成後,執行 Derive() 構造方法體 → 輸出 "Derive()"。
若包含靜態字段/靜態初始化塊,順序為:
靜態初始化在類加載階段(Class.forName、new 對象、訪問靜態成員時)觸發,僅執行一次。