首頁  >  文章  >  Java  >  程式碼區塊和構造器在Java物件初始化時的呼叫順序是什麼?

程式碼區塊和構造器在Java物件初始化時的呼叫順序是什麼?

王林
王林轉載
2023-05-10 09:52:081082瀏覽

    程式碼載入的優先順序 

    靜態程式碼區塊、靜態成員變數->非靜態程式碼區塊、非靜態成員變數->new其他物件呼叫對應物件建構方法(在本地物件的方法外包含建構方法)->new本地物件呼叫建構方法。

    注意:若new物件時,該物件中有靜態程式碼區塊和非靜態程式碼區塊,每new一次對象,非靜態程式碼區塊都會執行一次,但靜態程式碼區塊只會執行一次往後new物件都不會再執行。 】 

     建構方法的執行順序建構方法的執行順序區塊> 父類別建構程式碼區塊、建構方法> ; 子類別的建構程式碼區塊、建構方法 

    各種程式碼區塊的定義 

    # 靜態程式碼區塊 

    class Demo{ static { //静态代码块...... } }

    特點:  1、Java靜態程式碼區塊中的程式碼會在類別載入JVM時運行,且只被執行一次2、靜態區塊常用來執行類別屬性的初始化,和一些全域初始化的工作3、靜態區塊優先於各種程式碼區塊以及建構函數,如果一個類中有多個靜態程式碼區塊,會依照書寫順序依序執行4、靜態程式碼區塊可以定義在類別的任何地方中除了方法體中【這裡的方法體是任何方法體】 5、靜態程式碼區塊不能存取普通變數

    關於靜態程式碼區塊再詳細介紹下

    靜態程式碼區塊:在java中使用static關鍵字宣告的程式碼區塊。靜態塊用於初始化類別,為類別的屬性初始化。每個靜態程式碼區塊只會執行一次。

    由於JVM在載入類別時會執行靜態程式碼區塊,所以靜態程式碼區塊先於主方法執行。如果類別中包含多個靜態程式碼區塊,那麼將按照"先定義的程式碼先執行,然後再定義的程式碼後執行"。 【注意:1 靜態程式碼區塊不能存在於任何方法體內。 2 靜態程式碼區塊不能直接存取靜態實例變數和實例方法,需要透過類別的實例物件來存取。 】 實例代碼塊 實例代碼塊 又叫 構造初始化塊 , 構造代碼塊 , 初始化塊 。

    class Demo{ { //实例代码块...... } }

    特點:

      1、建構程式碼區塊在建立物件時被調用,每次建立物件都會呼叫一次
    • 2、建構程式碼區塊優先於建構子執行,同時建構程式碼區塊的運行依賴建構子
    • 3、
    • 建構程式碼區塊在類別中定義

    • 局部程式碼區塊

    局部程式碼區塊又叫普通程式碼區塊, 方法程式碼區塊

    class Demo{ public void test(){ { //局部代码块...... } } }

    特點: 1、普通代碼塊定義在方法體中2、普通代碼塊與實例代碼塊的格式一致都是{} 3、普通代碼塊與構造代碼塊唯一能直接看出的區別是構造代碼塊是在類中定義的,而普通程式碼區塊是在方法體中定義的4、可以限定變數生命週期,及早釋放,提高記憶體使用率

    驗證各程式碼區塊的執行順序

    範例程式碼如下:

    class Init {
        public Init() {
            System.out.println("无参构造器");
        }
        public Init(int a) {
            System.out.println("有参构造器");
        }
        {
            System.out.println("实例代码块1");
        }
        {
            System.out.println("实例代码块2");
        }
        {
            System.out.println("实例代码块3");
        }
        static {
            System.out.println("静态初始化块1");
        }
     
        static {
            System.out.println("静态初始化块2");
        }
    
        public void method(){
        	{
        		System.out.println("普通初始化块");
        	}
        }
    }

    測試程式碼如下:

    class Demo {
        public static void main(String[] args) {
            Init init1 = new Init();
            init1.method();
            System.out.println("------------");
            Init init2 = new Init();
            init2.method();
            //多打印几个对象的目的是:方便看出Static静态代码块 是否只执行一次!!!
            System.out.println("------------");
            Init init3 = new Init();
            init3.method();
        }
    }

    執行結果如下圖:

    程式碼區塊和構造器在Java物件初始化時的呼叫順序是什麼?

    結論:

    執行順序為:靜態程式碼區塊>實例程式碼區塊> 建構子>普通程式碼區塊,

    且靜態程式碼區塊,類別載入的時候就會調用,並且只調用一次(隨著類別的載入而執行)。

    那麼類別什麼時候會被載入呢?

    - 建立物件實例時(new)

    - 建立子類別物件實例,父類別也會被載入

    - 使用類別的靜態成員時(靜態屬性,靜態方法)

    驗證存在繼承關係中各程式碼區塊的執行順序

    範例繼承關係為 

    Three——> Two——> One

    ,

    #程式碼如下:

    class One {
        public One() {
            System.out.println("One构造器");
        }
     
        {
            System.out.println("One实例化块");
        }
     
        static {
            System.out.println("One静态代码块");
     
        }
     
    }
    class Two extends One {
     
        public Two() {
            System.out.println("Two构造器");
        }
     
        {
            System.out.println("Two实例化块");
        }
     
        static {
            System.out.println("Two静态代码块");
        }
     
    }
     
    class Three extends Two {
     
        public Three() {
            System.out.println("Three构造器");
        }
     
        {
            System.out.println("Three实例化块");
        }
        static {
            System.out.println("Three静态代码块");
        }
     
    }
    //测试代码 如下:
    public class Demo {
        public static void main(String[] args) {
            Three three = new Three();
            System.out.println("-----");
            Three three1 = new Three(); //重复执行的目的是为了 验证static是否只执行一次
            System.out.println("-----");
            Two three2 = new Three();   //验证 多态的情况下 用后面的类进行初始化 结果和上面一样
        }
    }

    程式碼區塊和構造器在Java物件初始化時的呼叫順序是什麼?

    #根據執行結果可知,在多個類別的繼承中存在初始化區塊、靜態初始化區塊、建構器,執行真實順序為:先後執行父類別A的靜態區塊,父類別B的靜態區塊,最後子類別的靜態區塊,然後執行父類別A的實例程式碼區塊和建構器,然後是B類的實例程式碼區塊和建構器,最後執行子類別C的實例程式碼區塊和建構器【註:這裡的ABC對應One、Two、Three 】

    結論:

    多個類別的繼承中初始化區塊、靜態初始化區塊、建構器的執行順序為:

    父类静态块——>子类静态块——>父类实例代码块——>父类构造器——>子类实例代码块——>子类构造器 ——>(如果有局部代码块, 再正常执行即可, 这里就没必要进行测试了)

    通过字节码深究实例代码块优先于构造器原因

    我们那一段代码作为例子说明下,代码如下:

    class Init {
        public Init() {
            System.out.println("无参构造器");
        }
        public Init(int a) {
            System.out.println("有参构造器");
     
        }
     
        {
            System.out.println("实例代码块1");
        }
     
        {
            System.out.println("实例代码块2");
        }
     
        {
            System.out.println("实例代码块3");
        }
     
        static {
            System.out.println("静态初始化块1");
        }
     
        static {
            System.out.println("静态初始化块2");
        }
     
        public void method(){
            {
                System.out.println("普通初始化块");
            }
        }
    }

    接下来让我们看看 , Init.java编译完的的字节码文件(Init.class)

    程式碼區塊和構造器在Java物件初始化時的呼叫順序是什麼?

    从这个字节码文件就可以很清晰的看出, 实例代码块实际上是被依次放到了构造方法的第一句, 所以可以的出此结论: 实例代码块的执行顺序是优先于构造器的。

    以上是程式碼區塊和構造器在Java物件初始化時的呼叫順序是什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述:
    本文轉載於:yisu.com。如有侵權,請聯絡admin@php.cn刪除