前言 在Java中,Static靜態代碼塊、構造代碼塊、普通代碼塊、構造函數的執行順序是一個java學習者必須掌握的基礎,本篇博客旨在讓你們能清除了解它們之間的執行順序。javascript
基本上代碼塊分爲三種:Static靜態代碼塊、構造代碼塊、普通代碼塊java
代碼塊執行順序靜態代碼塊——> 構造代碼塊 ——> 構造函數——> 普通代碼塊 函數
繼承中代碼塊執行順序:父類靜態塊——>子類靜態塊——>父類代碼塊——>父類構造器——>子類代碼塊——>子類構造器學習
Java靜態代碼塊中的代碼會在類加載JVM時運行,且只被執行一次,也就是說這些代碼不須要實例化類就可以被調用。通常狀況下,若是有些代碼必須在項目啓動的時候就執行的時候,就須要使用靜態代碼塊,因此靜態塊經常使用來執行類屬性的初始化!測試
關於Static靜態代碼塊的五個小結點ui
一、Java靜態代碼塊中的代碼會在類加載JVM時運行,且只被執行一次 二、靜態塊經常使用來執行類屬性的初始化 三、靜態塊優先於各類代碼塊以及構造函數,若是一個類中有多個靜態代碼塊,會按照書寫順序依次執行 四、靜態代碼塊能夠定義在類的任何地方中除了方法體中【這裏的方法體是任何方法體】 五、靜態代碼塊不能訪問普通變量spa
針對4中描述靜態代碼塊不能存在任何方法體中的緣由其實也是很簡單,因爲普通方法是經過加載類,而後new出實例化對象,經過對象才能運行這個方法,而靜態代碼塊只須要加載類以後就能運行了。對於靜態方法,在類加載的時候,靜態方法也已經加載了,可是咱們必需要經過類名或者對象名才能訪問,也就是說相比於靜態代碼塊,靜態代碼塊是本身主動運行的,而靜態方法是被動調用運行的。不論是哪一種方法,咱們須要明確靜態代碼塊的存在在類加載的時候就自動運行了,而放在不論是普通方法仍是靜態方法中,都是不能自動運行的。code
針對5中描述靜態代碼塊不能訪問普通變量,緣由一樣簡單。普通變量是被實例對象調用的,靜態代碼塊中都不存在其實例對象,談何調用變量?對象
Static靜態代碼塊使用格式繼承
static{
..............
}
複製代碼
聽這名字就知道和構造方法離不開!沒錯,可是仍是和構造方法有着本質區別,咱們都知道,沒個方法中均可以有不少構造方法,每建立一個對象其構造方法就執行一個,而一個構造方法能夠建立N個對象,構造方法就比較「高冷」了,而構造代碼塊就比較「舔狗」了,只要該類實例了一個對象,構造代碼就執行一次,利用每次建立對象的時候都會提早調用一次構造代碼塊特性,因此它能夠作統計建立對象的次數功能。固然構造代碼塊用的相對少!
構造代碼塊小結:
一、構造代碼塊在建立對象時被調用,每次建立對象都會調用一次 二、構造代碼塊優先於構造函數執行,同時構造代碼塊的運行依賴於構造函數 三、構造代碼塊在類中定義
針對2中的「依賴」可理解爲若是不實例化對象(也就是不執行構造方法),構造代碼塊是不會執行的!
代碼塊小結
一、普通代碼塊定義在方法體中 二、普通代碼塊與構造代碼塊的格式一致都是
{}
三、普通代碼塊與構造代碼塊惟一能直接看出的區別是構造代碼塊是在類中定義的,而普通代碼塊是在方法體中定義的
以上已經講得差很少了,開始上代碼了!
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
對應BaseOne
、BaseTwo
、BaseThree
】
結論:多個類的繼承中初始化塊、靜態初始化塊、構造器的執行順序爲:父類靜態塊——>子類靜態塊——>父類代碼塊——>父類構造器——>子類代碼塊——>子類構造器
若是本文對你有所幫助,請支持一下點個讚唄QnQ 最後,博主並非什麼大牛,也會犯錯!若有不正之處歡迎指正!感激涕零!