什麼叫代碼塊(Code Block)?用大括號把多行代碼封裝在一起,形成一個獨立的數據體,實現特定算法的代碼集合即為代碼塊,一般來說代碼塊是不能單獨運行的,必須要有運行主體。在Java中一共有四種類型的代碼塊:
(1)普通代碼塊
就是在方法後面使用「{}」括起來的代碼片段,它不能單獨執行,必須通過方法名調用執行。
(2)靜態代碼塊
在類中使用static修飾,並使用「{}」括起來的代碼片段,用於靜態變量的初始化或對像創建前的環境初始化。
(3)同步代碼塊
使用synchronized關鍵字修飾,並使用「{}」括起來的代碼片段,它表示同一時間只能有一個線程進入到該方法塊中,是一種多線程保護機制。
(4)構造代碼塊
在類中沒有任何的前綴或後綴,並使用「{}」括起來的代碼片段。
我們知道,一個類至少有一個構造函數(如果沒有,編譯器會無私地為其創建一個無參構造函數),構造函數是在對像生成時調用的,那現在的問題來了:構造函數和構造代碼塊是什麼關係?構造代碼塊是在什麼時候執行的?在回答這個問題之前,我們先來看看編譯器是如何處理構造代碼塊的,看如下代碼:
public class Client{
{
//構造代碼塊
System.out.println("執行構造代碼塊");
}
public Client(){
System.out.println("執行無參構造");
}
public Client(String_str){
System.out.println("執行有參構造");
}
}
這是一段非常簡單的代碼,它包含了構造代碼塊、無參構造、有參構造,我們知道代碼塊不具有獨立執行的能力,那麼編譯器是如何處理構造代碼塊呢?很簡單,編譯器會把構造代碼塊插入到每個構造函數的最前端,上面的代碼與如下代碼等價:
public class Client{
public Client(){
System.out.println("執行構造代碼塊");
System.out.println("執行無參構造");
}
public Client(String_str){
System.out.println("執行構造代碼塊");
System.out.println("執行有參構造");
}
}
每個構造函數的最前端都被插入了構造代碼塊,很顯然,在通過new關鍵字生成一個實例時會先執行構造代碼塊,然後再執行其他代碼,也就是說:構造代碼塊會在每個構造函數內首先執行(需要注意的是:構造代碼塊不是在構造函數之前運行的,它依托於構造函數的執行),明白了這一點,我們就可以把構造代碼塊應用到如下場景中:
(1)初始化實例變量(Instance Variable)
如果每個構造函數都要初始化變量,可以通過構造代碼塊來實現。當然也可以通過定義一個方法,然後在每個構造函數中調用該方法來實現,沒錯,可以解決,但是要在每個構造函數中都調用該方法,而這就是其缺點,若採用構造代碼塊的方式則不用定義和調用,會直接由編譯器寫入到每個構造函數中,這才是解決此類問題的絕佳方式。
(2)初始化實例環境
一個對像必須在適當的場景下才能存在,如果沒有適當的場景,則就需要在創建對像時創建此場景,例如在JEE開發中,要產生HTTP Request必須首先建立HTTP Session,在創建HTTP Request時就可以通過構造代碼塊來檢查HTTP Session是否已經存在,不存在則創建之。
以上兩個場景利用了構造代碼塊的兩個特性:在每個構造函數中都運行和在構造函數中它會首先運行。很好地利用構造代碼塊的這兩個特性不僅可以減少代碼量,還可以讓程序更容易閱讀,特別是當所有的構造函數都要實現邏輯,而且這部分邏輯又很複雜時,這時就可以通過編寫多個構造代碼塊來實現。每個代碼塊完成不同的業務邏輯(當然了,構造函數盡量簡單,這是基本原則),按照業務順序依次存放,這樣在創建實例對像時JVM也就會按照順序依次執行,實現複雜對象的模塊化創建。