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

Tips

  • 非靜態初始化塊基本和構造函數一個做用,能夠避免構造函數的代碼重複。初始化塊在類的每次構造都會執行
  • 靜態初始化塊只在類加載執行一次

一個有意思的盲區:html

執行psvm的時候,類的構造函數並不會執行,也就是說這時候類的實例並不存在。java

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初始化塊也被執行了;spa

  • 全部的靜態初始化塊都優先執行,其次纔是非靜態的初始化塊和構造函數,它們的執行順序是:調試

    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/…code

相關文章
相關標籤/搜索