1. 程式人生 > >2.3java基礎 程式碼塊

2.3java基礎 程式碼塊

public class Test {
    {
        ////
    }
}

      這種形式的程式段我們將其稱之為程式碼塊,所謂程式碼塊就是用大括號({})將多行程式碼封裝在一起,形成一個獨立的資料體,用於實現特定的演算法。一般來說程式碼塊是不能單獨執行的,它必須要有執行主體。在Java中程式碼塊主要分為四種:

一、 普通程式碼塊

      普通程式碼塊是我們用得最多的也是最普遍的,它就是在方法名後面用{}括起來的程式碼段。普通程式碼塊是不能夠單獨存在的,它必須要緊跟在方法名後面。同時也必須要使用方法名呼叫它。

public class Test {
    public void test(){
        System.out.println("普通程式碼塊");
    }
}

二、 靜態程式碼塊

      想到靜態我們就會想到static,靜態程式碼塊就是用static修飾的用{}括起來的程式碼段,它的主要目的就是對靜態屬性進行初始化。

public class Test {
    static{
        System.out.println("靜態程式碼塊");
    }
}

三、 同步程式碼塊

      使用 synchronized 關鍵字修飾,並使用“{}”括起來的程式碼片段,它表示同一時間只能有一個執行緒進入到該方法塊中,是一種多執行緒保護機制。

四、 構造程式碼塊

      在類中直接定義沒有任何修飾符、字首、字尾的程式碼塊即為構造程式碼塊。我們明白一個類必須至少有一個建構函式,建構函式在生成物件時被呼叫。構造程式碼塊和建構函式一樣同樣是在生成一個物件時被呼叫,那麼構造程式碼在什麼時候被呼叫?如何呼叫的呢?看如下程式碼:

public class Test {
    /**
     * 構造程式碼
     */
    {
        System.out.println("執行構造程式碼塊...");
    }
    
    /**
     * 無參建構函式
     */
    public Test(){
        System.out.println("執行無參建構函式...");
    }
    
    /**
     * 有參建構函式
     * @param id  id
     */
    public Test(String id){
        System.out.println("執行有參建構函式...");
    }
}

      上面定義了一個非常簡單的類,該類包含無參建構函式、有參建構函式以及構造程式碼塊,同時在上面也提過程式碼塊是沒有獨立執行的能力,他必須要有一個可以承載的載體,那麼編譯器會如何來處理構造程式碼塊呢?編譯器會將程式碼塊按照他們的順序(假如有多個程式碼塊)插入到所有的建構函式的最前端,這樣就能保證不管呼叫哪個建構函式都會執行所有的構造程式碼塊。上面程式碼等同於如下形式:

public class Test {
    /**
     * 無參建構函式
     */
    public Test(){
        System.out.println("執行構造程式碼塊...");
        System.out.println("執行無參建構函式...");
    }
    
    /**
     * 有參建構函式
     * @param id  id
     */
    public Test(String id){
        System.out.println("執行構造程式碼塊...");
        System.out.println("執行有參建構函式...");
    }

}

      執行結果

public static void main(String[] args) {
        new Test();
        System.out.println("----------------");
        new Test("1");
    }
------------
Output:
執行構造程式碼塊...
執行無參建構函式...
----------------
執行構造程式碼塊...
執行有參建構函式...

      從上面的執行結果可以看出在new一個物件的時候總是先執行構造程式碼,再執行建構函式,但是有一點需要注意構造程式碼不是在建構函式之前執行的,它是依託建構函式執行的。正是由於構造程式碼塊有這幾個特性,所以它常用於如下場景:

      1、 初始化例項變數

      如果一個類中存在若干個建構函式,這些建構函式都需要對例項變數進行初始化,如果我們直接在建構函式中例項化,必定會產生很多重複程式碼,繁瑣和可讀性差。這裡我們可以充分利用構造程式碼塊來實現。這是利用編譯器會將構造程式碼塊新增到每個建構函式中的特性。

      2、 初始化例項環境

      一個物件必須在適當的場景下才能存在,如果沒有適當的場景,則就需要在建立物件時建立此場景。我們可以利用構造程式碼塊來建立此場景,尤其是該場景的建立過程較為複雜。構造程式碼會在建構函式之前執行。

      上面兩個常用場景都充分利用構造程式碼塊的特性,能夠很好的解決在例項化物件時建構函式比較難解決的問題,利用構造程式碼不僅可以減少程式碼量,同時也是程式的可讀性增強了。特別是當一個物件的建立過程比較複雜,需要實現一些複雜邏輯,這個時候如果在建構函式中實現邏輯,這是不推薦的,因為我們提倡建構函式要儘可能的簡單易懂,所以我們可以使用構造程式碼封裝這些邏輯實現部分。

五、 靜態程式碼塊、構造程式碼塊、建構函式執行順序

      從詞面上我們就可以看出他們的區別。靜態程式碼塊,靜態,其作用級別為類,構造程式碼塊、建構函式,構造,其作用級別為物件。

      1、 靜態程式碼塊,它是隨著類的載入而被執行,只要類被載入了就會執行,而且只會載入一次,主要用於給類進行初始化。

      2、 構造程式碼塊,每建立一個物件時就會執行一次,且優先於建構函式,主要用於初始化不同物件共性的初始化內容和初始化例項環境。

      3、 建構函式,每建立一個物件時就會執行一次。同時建構函式是給特定物件進行初始化,而構造程式碼是給所有物件進行初始化,作用區域不同。

      通過上面的分析,他們三者的執行順序應該為:靜態程式碼塊 > 構造程式碼塊 > 建構函式。

public class Test {
    /**
     * 靜態程式碼塊
     */
    static{
        System.out.println("執行靜態程式碼塊...");
    }
    
    /**
     * 構造程式碼塊
     */
    {
        System.out.println("執行構造程式碼塊...");
    }
    
    /**
     * 無參建構函式
     */
    public Test(){
        System.out.println("執行無參建構函式...");
    }
    
    /**
     * 有參建構函式
     * @param id
     */
    public Test(String id){
        System.out.println("執行有參建構函式...");
    }
    
    public static void main(String[] args) {
        System.out.println("----------------------");
        new Test();
        System.out.println("----------------------");
        new Test("1");
    }
}
-----------
Output:
執行靜態程式碼塊...
----------------------
執行構造程式碼塊...
執行無參建構函式...
----------------------
執行構造程式碼塊...
執行有參建構函式...