static程式碼塊、構造程式碼塊、建構函式以及Java類初始化順序

weixin_34236869發表於2018-11-07

順序:
父類靜態塊-->子類靜態塊--> main方法-->父類構造程式碼塊 -->父類建構函式-->子類構造程式碼塊-->子類建構函式,同一級別程式碼塊按順序執行。

這幾個名詞體現在程式碼中,如下:

class Study {
    public Study(){
        System.out.println("建構函式");    
    }
    {
        System.out.println("構造程式碼塊");    
    }
    static {
        System.out.println("靜態程式碼塊");        
    }
}

靜態程式碼塊和程式碼塊的區別在於:
靜態程式碼塊只執行一次,程式碼塊每次建立該物件的時候都會執行一次。
執行順序:
靜態變數,main方法,構造塊,建構函式。

我覺得對於這個簡單明瞭的理解就是上程式碼。

普通情況

  • 執行順序,靜態變數-->靜態塊--> main方法
public class Demo {    
    static int a = 10;
    static {
         System.out.println("a----"+a);
         System.out.println("A的靜態程式碼塊");
    }
    public static void main(String[] args){
         System.out.println("main");
    }
}

輸出結果:
a----10
A的靜態程式碼塊
main
  • main方法 --> 非靜態變數--> 構造程式碼塊 --> 建構函式
public class Demo { 
    static int a = 10;
    static {
         System.out.println("a----"+a);
         System.out.println("A的靜態程式碼塊");
    }
    int b = 20;
    {
         System.out.println("b----"+b);
         System.out.println("A的構造程式碼塊");
    }
    Demo(){
        System.out.println("建構函式");
    }
    public static void main(String[] args){
         System.out.println("main");
         new Demo();
    }
}

輸出結果:
a----10
A的靜態程式碼塊
main
b----20
A的構造程式碼塊
建構函式
  • 靜態構造塊只執行一次,構造程式碼塊每次new物件的時候都會呼叫。
public class Demo { 

    static {
        System.out.println("子類的靜態程式碼塊");
    }
    
    {
        System.out.println("子類的構造程式碼塊");
    }
    Demo(){
        System.out.println("子類建構函式");
    }

    public static void main(String[] args){
        new Demo();
        new Demo();
    }
}

結果:
子類的靜態程式碼塊
子類的構造程式碼塊
子類建構函式
子類的構造程式碼塊
子類建構函式

為什麼只靜態程式碼塊只執行了一次,普通程式碼塊執行了多次?
靜態變數被所有的物件所共享,在記憶體中只有一個副本,它當且僅當在類初次載入時會被初始化。而非靜態變數是物件所擁有的,在建立物件的時候被初始化,存在多個副本,各個物件擁有的副本互不影響。

繼承情況

  • 父類靜態塊-->子類靜態塊--> main方法-->父類構造程式碼塊 -->父類建構函式-->子類構造程式碼塊--> 子類建構函式
class Super {
    static {
        System.out.println("Super的靜態程式碼塊");
    }
    {
        System.out.println("Super的構造程式碼塊");
    }
    Super(){
        System.out.println("Super建構函式");
    }

}

public class Demo extends Super{
    static {
        System.out.println("子類的靜態程式碼塊1");
    }

    static {
        System.out.println("子類的靜態程式碼塊2");
    }
    
    {
        System.out.println("子類的構造程式碼塊");
    }
    Demo(){
        System.out.println("子類建構函式");
    }

    public static void main(String[] args){
        System.out.println("main");
        new Demo();
    }

}

輸出:
Super的靜態程式碼塊
子類的靜態程式碼塊1
子類的靜態程式碼塊2
main
Super的構造程式碼塊
Super建構函式
子類的構造程式碼塊
子類建構函式

為什麼會呼叫父類的建構函式呢?命名沒有呼叫過Super方法。
-->子類建構函式會預設呼叫一下父類的無參建構函式,可以給父類建構函式加個引數試一下。基礎知識不能忘啊。

載入過程:
在執行開始,先要尋找到main方法,因為main方法是程式的入口,但是在執行main方法之前,必須先載入Demo類,而在載入Demo類的時候發現Demo類繼承自Super類,因此會轉去先載入Super類,在載入Super類的時候,發現有static塊,便執行了static塊。在Super類載入完成之後,便繼續載入Demo類,然後發現Demo類中也有static塊,便執行static塊。在載入完所需的類之後,便開始執行main方法。在main方法中執行new Demo()的時候會先呼叫父類的構造器,然後再呼叫自身的構造器。因此,便出現了上面的輸出結果。
同時存在兩個程式碼塊的時候,按程式碼順序執行。

題目

public class Demo {
    private static Demo test = new Demo();
    //靜態變數sta1    未賦予初始值
    public static int sta1;
    //靜態變數sta1    賦予初始值20
    public static int sta2 = 20;
    //構造方法中對於靜態變數賦值
    private Demo() {
        sta1 ++ ;
        sta2 ++ ;
    }
    public static void main(String[] args) {
        System.out.println(Demo.sta1);
        System.out.println(Demo.sta2);
    }
}

print:
1
20
res:都是static就順序執行,執行完後,讓sta1和2自增,完後sta2又賦值為20。
補充一個demo

構造程式碼塊和物件繫結,簡單講,不new物件不走構造程式碼塊


public class Animal {
    private static int k;
    static{
        System.out.println("父類的靜態方法");
    }
    {
        System.out.println("執行父類的構造程式碼塊");
    }
    public Animal(){
        System.out.println("執行父類的構造方法");
    }
    public static void main(String[] args) {
        System.out.println(Animal.k);
    }
}
print:
父類的靜態方法
0

這個連結裡面也有幾道燒腦的題目,反正就按順序來就好了,但是寫程式碼的時候最好還是以大部分人能看明白為主,要不然光這個點很多人就得進坑,而且時間久了自己也會記不牢。
https://www.cnblogs.com/chihirotan/p/6043442.html

相關文章