Java中靜態程式碼塊、構造程式碼塊、建構函式、普通程式碼塊

時光機jay發表於2020-09-26

  在Java中,靜態程式碼塊、構造程式碼塊、建構函式、普通程式碼塊的執行順序是一個筆試的考點,通過這篇文章希望大家能徹底瞭解它們之間的執行順序。

回到頂部

1、靜態程式碼塊

  ①、格式

  在java類中(方法中不能存在靜態程式碼塊)使用static關鍵字和{}宣告的程式碼塊:

1

2

3

4

5

public class CodeBlock {

    static{

        System.out.println("靜態程式碼塊");

    }

}

  ②、執行時機

  靜態程式碼塊在類被載入的時候就執行了,而且只執行一次,並且優先於各種程式碼塊以及建構函式。如果一個類中有多個靜態程式碼塊,會按照書寫順序依次執行。後面在比較的時候會通過具體例項來證明。

  ③、靜態程式碼塊的作用

  一般情況下,如果有些程式碼需要在專案啟動的時候就執行,這時候就需要靜態程式碼塊。比如一個專案啟動需要載入的很多配置檔案等資源,我們就可以都放入靜態程式碼塊中。

  ④、靜態程式碼塊不能存在任何方法體中

  這個應該很好理解,首先我們要明確靜態程式碼塊是在類載入的時候就要執行了。我們分情況討論:

  對於普通方法,由於普通方法是通過載入類,然後new出例項化物件,通過物件才能執行這個方法,而靜態程式碼塊只需要載入類之後就能執行了。

  對於靜態方法,在類載入的時候,靜態方法也已經載入了,但是我們必須要通過類名或者物件名才能訪問,也就是說相比於靜態程式碼塊,靜態程式碼塊是主動執行的,而靜態方法是被動執行的。

  不管是哪種方法,我們需要明確靜態程式碼塊的存在在類載入的時候就自動執行了,而放在不管是普通方法還是靜態方法中,都是不能自動執行的。

  ⑤、靜態程式碼塊不能訪問普通變數

  這個理解思維同上,普通變數只能通過物件來呼叫,是不能放在靜態程式碼塊中的。

回到頂部

2、構造程式碼塊

  ①、格式

  在java類中使用{}宣告的程式碼塊(和靜態程式碼塊的區別是少了static關鍵字):

1

2

3

4

5

6

7

8

public class CodeBlock {

    static{

        System.out.println("靜態程式碼塊");

    }

    {

        System.out.println("構造程式碼塊");

    }

}

  ②、執行時機

  構造程式碼塊在建立物件時被呼叫,每次建立物件都會呼叫一次,但是優先於建構函式執行。需要注意的是,聽名字我們就知道,構造程式碼塊不是優先於建構函式執行,而是依託於建構函式,也就是說,如果你不例項化物件,構造程式碼塊是不會執行的。怎麼理解呢?我們看看下面這段程式碼:

1

2

3

4

5

6

7

8

9

10

11

12

public class CodeBlock {

    {

        System.out.println("構造程式碼塊");

    }

     

    public CodeBlock(){

        System.out.println("無參建構函式");

    }

    public CodeBlock(String str){

        System.out.println("有參建構函式");

    }

}

  我們反編譯生成的class檔案:

  

  如果存在多個構造程式碼塊,則執行順序按照書寫順序依次執行。

  ③、構造程式碼塊的作用

   和建構函式的作用類似,都能對物件進行初始化,並且只要建立一個物件,構造程式碼塊都會執行一次。但是反過來,建構函式則不一定每個物件建立時都執行(多個建構函式情況下,建立物件時傳入的引數不同則初始化使用對應的建構函式)。

  利用每次建立物件的時候都會提前呼叫一次構造程式碼塊特性,我們可以做諸如統計建立物件的次數等功能。

回到頂部

3、建構函式 

  1.建構函式的命名必須和類名完全相同。在java中普通函式可以和建構函式同名,但是必須帶有返回值;

  2.建構函式的功能主要用於在類的物件建立時定義初始化的狀態。它沒有返回值,也不能用void來修飾。這就保證了它不僅什麼也不用自動返回,而且根本不能有任何選擇。而其他方法都有返回值,即使是void返回值。儘管方法體本身不會自動返回什麼,但仍然可以讓它返回一些東西,而這些東西可能是不安全的;

  3.建構函式不能被直接呼叫,必須通過new運算子在建立物件時才會自動呼叫;而一般的方法是在程式執行到它的時候被呼叫的;

  4.當定義一個類的時候,通常情況下都會顯示該類的建構函式,並在函式中指定初始化的工作也可省略,不過Java編譯器會提供一個預設的建構函式.此預設建構函式是不帶引數的。而一般的方法不存在這一特點;

回到頂部

4、普通程式碼塊

  普通程式碼塊和構造程式碼塊的區別是,構造程式碼塊是在類中定義的,而普通程式碼塊是在方法體中定義的。且普通程式碼塊的執行順序和書寫順序一致。

1

2

3

4

5

public void sayHello(){

    {

        System.out.println("普通程式碼塊");

    }

}

回到頂部

5、執行順序

  •  靜態程式碼塊>構造程式碼塊>建構函式>普通程式碼塊 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

public class CodeBlock {

    static{

        System.out.println("靜態程式碼塊");

    }

    {

        System.out.println("構造程式碼塊");

    }

    public CodeBlock(){

        System.out.println("無參建構函式");

    }

     

    public void sayHello(){

        {

            System.out.println("普通程式碼塊");

        }

    }

     

    public static void main(String[] args) {

        System.out.println("執行了main方法");

         

        new CodeBlock().sayHello();;

        System.out.println("---------------");

        new CodeBlock().sayHello();;

    }

}

  反編譯生成的class檔案:

  

 

  執行結果:

   

  我們建立了兩個匿名物件,但是靜態程式碼塊只是呼叫了一次。

回到頂部

6、父類和子類執行順序

  物件的初始化順序:

  首先執行父類靜態的內容,父類靜態的內容執行完畢後,接著去執行子類的靜態的內容,當子類的靜態內容執行完畢之後,再去看父類有沒有構造程式碼塊,如果有就執行父類的構造程式碼塊,父類的構造程式碼塊執行完畢,接著執行父類的構造方法;父類的構造方法執行完畢之後,它接著去看子類有沒有構造程式碼塊,如果有就執行子類的構造程式碼塊。子類的構造程式碼塊執行完畢再去執行子類的構造方法。

  總之一句話,靜態程式碼塊內容先執行,接著執行父類構造程式碼塊和構造方法,然後執行子類構造程式碼塊和構造方法。

  父類:SuperClass.java

+ View Code

  子類:SubClass.java

+ View Code

  測試:

+ View Code

  列印結果:

  


相關文章