1. 程式人生 > 程式設計 >Static靜態程式碼塊以及各程式碼塊之間的執行順序

Static靜態程式碼塊以及各程式碼塊之間的執行順序

前言 在Java中,Static靜態程式碼塊、構造程式碼塊、普通程式碼塊、建構函式的執行順序是一個java學習者必須掌握的基礎,本篇部落格旨在讓大家能清除了解它們之間的執行順序。

程式碼塊的分類

基本上程式碼塊分為三種:Static靜態程式碼塊、構造程式碼塊、普通程式碼塊

程式碼塊執行順序靜態程式碼塊——> 構造程式碼塊 ——> 建構函式——> 普通程式碼塊

繼承中程式碼塊執行順序:父類靜態塊——>子類靜態塊——>父類程式碼塊——>父類構造器——>子類程式碼塊——>子類構造器

1、靜態程式碼塊(也叫靜態塊、靜態初始化塊)

Java靜態程式碼塊中的程式碼會在類載入JVM時執行,且只被執行一次,也就是說這些程式碼不需要例項化類就能夠被呼叫。一般情況下,如果有些程式碼必須在專案啟動的時候就執行的時候,就需要使用靜態程式碼塊,所以靜態塊常用來執行類屬性的初始化!

關於Static靜態程式碼塊的五個小結點

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

針對4中描述靜態程式碼塊不能存在任何方法體中的原因其實也是很簡單,由於普通方法是通過載入類,然後new出例項化物件,通過物件才能執行這個方法,而靜態程式碼塊只需要載入類之後就能運行了。對於靜態方法,在類載入的時候,靜態方法也已經載入了,但是我們必須要通過類名或者物件名才能訪問,也就是說相比於靜態程式碼塊,靜態程式碼塊是自己主動執行的,而靜態方法是被動呼叫執行的。不管是哪種方法,我們需要明確靜態程式碼塊的存在在類載入的時候就自動運行了

,而放在不管是普通方法還是靜態方法中,都是不能自動執行的。

針對5中描述靜態程式碼塊不能訪問普通變數,原因同樣簡單。普通變數是被例項物件呼叫的,靜態程式碼塊中都不存在其例項物件,談何呼叫變數?

Static靜態程式碼塊使用格式

static{
  ..............
}
複製程式碼

2、構造程式碼塊(也叫構造初始化塊)

聽這名字就知道和構造方法離不開!沒錯,但是還是和構造方法有著本質區別,我們都知道,沒個方法中都可以有很多構造方法,每建立一個物件其構造方法就執行一個,而一個構造方法可以建立N個物件,構造方法就比較“高冷”了,而構造程式碼塊就比較“舔狗”了,只要該類例項了一個物件,構造程式碼就執行一次,利用每次建立物件的時候都會提前呼叫一次構造程式碼塊特性,所以它可以做統計建立物件的次數功能。當然構造程式碼塊用的相對少!

構造程式碼塊小結

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

針對2中的“依賴”可理解為如果不例項化物件(也就是不執行構造方法),構造程式碼塊是不會執行的!

3、程式碼塊(又叫普通程式碼塊、初始化塊)

程式碼塊小結

1、普通程式碼塊定義在方法體中 2、普通程式碼塊與構造程式碼塊的格式一致都是{} 3、普通程式碼塊與構造程式碼塊唯一能直接看出的區別是構造程式碼塊是在類中定義的,而普通程式碼塊是在方法體中定義的

執行順序的程式碼測試

以上已經講得差不多了,開始上程式碼了!

package com.gx.initializationblock;

public class Initializationblock {

    int intA;
    int intB;


    public Initializationblock() {
        System.out.println("無參構造器00000000");
    }

    public Initializationblock(int a) {
        System.out.println("一個引數的構造器");
        
    }


    {
        intA = 10;
        intB = 15;

        System.out.println("構造初始化塊11111");
    }

    {
        System.out.println("構造初始化塊22222");
    }

    {
    	
        System.out.println("構造初始化塊33333");
    }

    //靜態初始化塊
    static {
        System.out.println("靜態初始化塊01010101");
    }

    static {
        System.out.println("靜態初始化塊0202020202");
    }
    public void method(){
    	{
    		System.out.println("普通初始化塊");
    	}
    }
}
複製程式碼

測試demo

package com.gx.initializationblock;

/* 初始化塊一
	 * 因為靜態塊是在類的初始化階段完成的,
	 * 因此在建立某個類的第二個物件時,該類的靜態塊就不會執行了
	 * 
	 * 在單個類中,靜態初始化塊,初始化塊,構造器
	 * 多個類的繼承中初始化塊、靜態初始化塊、構造器的執行順序
在繼承中,先後執行父類A的靜態塊,父類B的靜態塊,最後子類的靜態塊,然後再執行父類A的非靜態塊和構造器,然後是B類的非靜態塊和構造器,最後執行子類的非靜態塊和構造器
 */
public class Demo1 {
    public static void main(String[] args) {
        Initializationblock initializationblock = new Initializationblock();
        initializationblock.method();
        System.out.println("------------");
        //多列印幾個物件的目的是:好看出Static靜態程式碼塊只執行一次!!!
        Initializationblock initializationblock2 = new Initializationblock(); //因為靜態塊是在類的初始化階段完成的,因此在建立某個類的第二個物件時,該類的靜態塊就不會執行了
        initializationblock2.method();
        Initializationblock initializationblock3 = new Initializationblock();
        initializationblock3.method();
    }
}
複製程式碼

列印結果

靜態初始化塊01010101
靜態初始化塊0202020202
構造初始化塊11111
構造初始化塊22222
構造初始化塊33333
無參構造器00000000
普通初始化塊
------------
構造初始化塊11111
構造初始化塊22222
構造初始化塊33333
無參構造器00000000
普通初始化塊
構造初始化塊11111
構造初始化塊22222
構造初始化塊33333
無參構造器00000000
普通初始化塊
複製程式碼

得出結論:執行順序靜態程式碼塊 > 構造程式碼塊 > 建構函式 > 普通程式碼塊

繼承中各程式碼塊的執行順序

啥都不說了,直接擼程式碼:繼承關係為 BaseThree——> BaseTwo——> BaseOne BaseOne類

package com.gx.initializationblock;

public class BaseOne {

    public BaseOne() {
        System.out.println("BaseOne構造器");
    }

    {
        System.out.println("BaseOne初始化塊");
        System.out.println();
    }

    static {
        System.out.println("BaseOne靜態初始化塊");

    }

}
複製程式碼

BaseTwo類

package com.gx.initializationblock;

public class BaseTwo extends BaseOne {
    public BaseTwo() {
        System.out.println("BaseTwo構造器");
    }

    {
        System.out.println("BaseTwo初始化塊");
    }

    static {
        System.out.println("BaseTwo靜態初始化塊");
    }
}
複製程式碼

BaseThree 類

package com.gx.initializationblock;

public class BaseThree extends BaseTwo {
    public BaseThree() {
        System.out.println("BaseThree構造器");
    }

    {
        System.out.println("BaseThree初始化塊");
    }

    static {
        System.out.println("BaseThree靜態初始化塊");
    }
}
複製程式碼

測試demo2類

package com.gx.initializationblock;

/*
     注:這裡的ABC對應BaseOne、BaseTwo、BaseThree 
 * 多個類的繼承中初始化塊、靜態初始化塊、構造器的執行順序
     在繼承中,先後執行父類A的靜態塊,父類B的靜態塊,最後子類的靜態塊,
     然後再執行父類A的非靜態塊和構造器,然後是B類的非靜態塊和構造器,最後執行子類的非靜態塊和構造器
 */
public class Demo2 {
    public static void main(String[] args) {
        BaseThree baseThree = new BaseThree();
        System.out.println("-----");
        BaseThree baseThree2 = new BaseThree();

    }
}
複製程式碼

執行結果

BaseOne靜態初始化塊
BaseTwo靜態初始化塊
BaseThree靜態初始化塊
BaseOne初始化塊

BaseOne構造器
BaseTwo初始化塊
BaseTwo構造器
BaseThree初始化塊
BaseThree構造器
-----
BaseOne初始化塊

BaseOne構造器
BaseTwo初始化塊
BaseTwo構造器
BaseThree初始化塊
BaseThree構造器
複製程式碼

多個類的繼承中初始化塊、靜態初始化塊、構造器的執行順序為:先後執行父類A的靜態塊,父類B的靜態塊,最後子類的靜態塊,然後再執行父類A的非靜態塊和構造器,然後是B類的非靜態塊和構造器,最後執行子類的非靜態塊和構造器【注:這裡的ABC對應BaseOneBaseTwoBaseThree

結論:多個類的繼承中初始化塊、靜態初始化塊、構造器的執行順序為:父類靜態塊——>子類靜態塊——>父類程式碼塊——>父類構造器——>子類程式碼塊——>子類構造器

如果本文對你有所幫助,請支援一下點個讚唄QnQ 最後,博主並不是什麼大牛,也會犯錯!如有不正之處歡迎指正!感激不盡!