關於靜態塊、靜態屬性、構造塊、構造方法的執行順序


下面是在網上找到的比較典型的例子,以此來說明

例一:

class A {
    static {
        System.out.println("A的靜態塊");
    }
    private static String staticStr = getStaticStr();
    private String str = getStr();

    {
        System.out.println("A的實例塊");
    }
    
    public A() {
        System.out.println("A的構造方法");
    }

    private static String getStaticStr() {
        System.out.println("A的靜態屬性初始化");
        return null;
    }
    private String getStr() {
        System.out.println("A的實例屬性初始化");
        return null;
    }
    public static void main(String[] args) {
        new B();
        new B();
    }

}

class B extends A{
    private static String staticStr = getStaticStr();
    static {
        System.out.println("B的靜態塊");
    }
    {
        System.out.println("B的實例塊");
    }
    public B() {
        System.out.println("B的構造方法");
    }
   private String str = getStr();
private static String getStaticStr() { System.out.println("B的靜態屬性初始化"); return null; } private String getStr() { System.out.println("B的實例屬性初始化"); return null; } }

該段代碼的執行結果為:

A的靜態塊
A的靜態屬性初始化
B的靜態屬性初始化
B的靜態塊
A的實例屬性初始化
A的實例塊
A的構造方法
B的實例塊
B的實例屬性初始化
B的構造方法
A的實例屬性初始化
A的實例塊
A的構造方法
B的實例塊
B的實例屬性初始化
B的構造方法

由此可見,實例化子類的時候,若此類未被加載過,首先加載是父類的類對象,然后加載子類的類對象,接着實例化父類,最后實例化子類,若此類被加載過,不再加載父類和子類的類對象。

接下來是加載順序,當加載類對象時,首先初始化靜態屬性,然后執行靜態塊;當實例化對象時,首先執行構造塊(直接寫在類中的代碼塊),然后執行構造方法。至於各靜態塊和靜態屬性初始化哪個些執行,是按代碼的先后順序。屬性、構造塊(也就是上面的實例塊)、構造方法之間的執行順序(但構造塊一定會在構造方法前執行),也是按代碼的先后順序。


 

例二:

public class EXA {
    private static EXA a = new EXA();  
    static {  
        System.out.println("父類--靜態代碼塊");  
    }  
  
    public EXA() {  
        System.out.println("父類--構造函數");  
    }  
  
    {  
        System.out.println("父類--非靜態代碼塊");  
    }  
  
    public static void main(String[] args) {
        new EXC();
        new EXC();
    }
}

class EXC extends EXA {  
    private static EXC b = new EXC();  
    static {  
        System.out.println("子類--靜態代碼塊");  
    }  
    {  
        System.out.println("子類--非靜態代碼塊");  
    }  
  
    public EXC() {  
        System.out.println("子類--構造函數");  
    }
}

該段代碼的執行結果為:

父類--非靜態代碼塊
父類--構造函數
父類--靜態代碼塊
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
子類--靜態代碼塊
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數

分析(非靜態代碼塊即構造塊):

首先要加載父類EXA,由於A的靜態屬性在靜態塊的前面,先初始化靜態屬性(new EXA())(父類--非靜態代碼塊;父類--構造函數),然后是靜態塊(父類--靜態代碼塊);

加載子類EXC,由於EXC的靜態屬性也在靜態塊的前面,先初始化靜態屬性(new EXC()),實例化子類對象的時候會先實例化父類,所以執行的順序為(父類--非靜態代碼塊;父類--構造函數;子類--非靜態代碼塊;子類--構造函數),然后是靜態塊(子類--靜態代碼塊)

實例化父類EXA對象:父類--非靜態代碼塊;父類--構造函數;

實例化子類EXC對象:子類--非靜態代碼塊;子類--構造函數;

第二個new EXC():因為父類和子類都已加載,只需依次實例化父類對象和子類對象(父類--非靜態代碼塊;父類--構造函數;子類--非靜態代碼塊;子類--構造函數;)

推測:若將EXA的靜態塊和靜態屬性的初始化換位置,執行結果應該為:

父類--靜態代碼塊
父類--非靜態代碼塊
父類--構造函數
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
子類--靜態代碼塊
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數
父類--非靜態代碼塊
父類--構造函數
子類--非靜態代碼塊
子類--構造函數

public class EXA {
      
    static {  
        System.out.println("父類--靜態代碼塊");  
    } 
    private static EXA a = new EXA();
  
    public EXA() {  
        System.out.println("父類--構造函數");  
    }  
  
    {  
        System.out.println("父類--非靜態代碼塊");  
    }  
  
    public static void main(String[] args) {
        new EXC();
        new EXC();
    }
}

class EXC extends EXA {  
    private static EXC b = new EXC();  
    static {  
        System.out.println("子類--靜態代碼塊");  
    }  
    {  
        System.out.println("子類--非靜態代碼塊");  
    }  
  
    public EXC() {  
        System.out.println("子類--構造函數");  
    }
}

運行發現,結果證實這樣。

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM