1. 程式人生 > 程式設計 >一文看懂靜態初始化塊、靜態成員、初始化塊、建構函式執行順序以及用途

一文看懂靜態初始化塊、靜態成員、初始化塊、建構函式執行順序以及用途

Tips

  • 非靜態初始化塊基本和建構函式一個作用,可以避免建構函式的程式碼重複。初始化塊在類的每次構造都會執行
  • 靜態初始化塊只在類載入執行一次

一個有意思的盲區:

執行psvm的時候,類的建構函式並不會執行,也就是說這時候類的例項並不存在。

public static void main(String[] args) {}
複製程式碼

測試執行順序

C extens B,B extends A , Main類中 new C()

public class InitLearn {

    static class A{
        static Print  pA1 =new Print("static pA1"
); static { System.out.println("Static Initialization Block A"); } static Print pA2 =new Print("static pA2"); { System.out.println("Initialization Block A Before Construct"); } public A(){ System.out.println("Construct A"
); } { System.out.println("Initialization Block A After Construct"); } }; static class B extends A{ static Print pB1 =new Print("static pB1"); static Print pB2 =new Print("static pB2"); static { System.out.println("Static Initialization Block B"
); } { System.out.println("Initialization Block B Before Construct"); } public B(){ System.out.println("Construct B"); } { System.out.println("Initialization Block B After Construct"); } }; static class C extends B{ static Print pC1 =new Print("static pC1"); static { System.out.println("Static Initialization Block C"); } static Print pC2 =new Print("static pC2"); { System.out.println("Initialization Block C Before Construct"); } public C(){ System.out.println("Construct C"); } { System.out.println("Initialization Block C After Construct"); } }; static class Print{ public Print(String v){ System.out.println(v); } } static { System.out.println("static{} of the class run psvm to test"); } public static void main(String[] args) { new C(); //new C(); } } 複製程式碼

輸出:


static{} of the class run psvm to test //測試類的靜態初始化塊,在呼叫psvmstatic pA1 //A類靜態成員 定義在靜態初始化塊前
Static Initialization Block A //A類靜態初始化塊
static pA2 //A類靜態成員 定義在靜態初始化塊後
static pB1 //B類靜態成員 定義在靜態初始化塊前
static pB2 //B類靜態成員 定義在靜態初始化塊前
Static Initialization Block B //B類靜態初始化塊
static pC1  //C類靜態成員 定義在靜態初始化塊前
Static Initialization Block C //C類靜態初始化塊
static pC2  //C類靜態成員 定義在靜態初始化塊後
Initialization Block A Before Construct //A類初始化塊
Initialization Block A After Construct  //A類初始化塊
Construct A  //A類構造方法
Initialization Block B Before Construct 
Initialization Block B After Construct
Construct B
Initialization Block C Before Construct
Initialization Block C After Construct
Construct C
    
    
複製程式碼

有趣的現象

  • InitLearn類是肯定沒有被例項化過的,但是由於執行main入口函式用到了InitLearn類,於是static初始化塊也被執行了;

  • 所有的靜態初始化塊都優先執行,其次才是非靜態的初始化塊和建構函式,它們的執行順序是:

    1. 父類的靜態初始化塊/靜態成員,順序是宣告順序
    2. 子類的靜態初始化塊/靜態成員,順序是宣告順序
    3. 父類的初始化塊(無論定義在構造方法前還是後)
    4. 父類的建構函式
    5. 子類的初始化塊(無論定義在構造方法前還是後)
    6. 子類的建構函式
  • 如果之後再new 一個B(),只會出現以下日誌,靜態的初始化過程只執行一次

    Initialization Block A Before Construct
    Initialization Block A After Construct
    Construct A
    Initialization Block B Before Construct
    Initialization Block B After Construct
    Construct B
    Initialization Block C Before Construct
    Initialization Block C After Construct
    Construct C
    複製程式碼

總結

  1. 靜態初始化塊的優先順序最高,也就是最先執行,並且僅在類第一次被載入時執行;
  2. 非靜態初始化塊和建構函式後執行,並且在每次生成物件時執行一次;
  3. 非靜態初始化塊的程式碼會在類建構函式之前執行。因此若要使用,應當養成把初始化塊寫在建構函式之前的習慣,便於除錯;
  4. 靜態初始化塊既可以用於初始化靜態成員變數,也可以執行初始化程式碼
  5. 非靜態初始化塊可以針對多個過載建構函式進行程式碼複用

參考

www.cnblogs.com/BlackStorm/…