類初始化過程是 Java 基礎知識,但從 字節碼層面 深入理解各場景下的執行順序,能揭示許多源碼層面難以察覺的細節。本文基於 JDK 1.8 環境,通過 javap -c 反編譯字節碼,分析四大典型場景:

代碼聲明四個成員變量與無參構造函數,右側為字節碼棧幀執行順序。
super(),決定了多重初始化順序(詳見場景四);myId1 聲明未賦值,構造函數中 myId1=100 才有指令;myId2 聲明即賦值,優先於構造函數執行初始化指令;myText2 = null 生成 aconst_null,構造函數中再次賦值又生成指令。null 非對象,JVM 中無明確類型,可視為「類型未定、未分配空間」的標志;
輸出結果:
text:null
text:text1-1

print 時,myText1 尚未初始化(含聲明賦值),故輸出 null;text1-1;

<clinit> 方法 中,執行順序 = 源碼出現順序;<clinit> 在類被 JVM 首次加載時調用一次,與實例化次數無關;myStaticId2 為非法(編譯報錯);(原文未展開,此處補充核心結論)
<clinit> 先於子類 <clinit> 執行**;1. 父類靜態變量/靜態代碼塊(按順序)
2. 子類靜態變量/靜態代碼塊(按順序)
3. 父類成員變量賦值/實例代碼塊(按順序)
4. 父類構造函數
5. 子類成員變量賦值/實例代碼塊(按順序)
6. 子類構造函數
掌握字節碼視角的初始化順序,能避開 90% 的初始化陷阱,是進階 Java 開發者的必備內功。