在程序編程中,可以直接使用“{}”定義一段語句。根據定義的位置以及聲明關鍵字的不同,可以分爲四種:普通代碼塊、構造代碼塊、靜態代碼塊和同步代碼塊。一般來說代碼塊是不能單獨運行的,它必須要有運行主體。
一、普通代碼塊
普通代碼塊是定義在方法之中的代碼塊。我們先觀察一下代碼:
package com.wz.thisdemo;
public class TestDemo {
public static void main(String args[]) {
if (true) {
int x = 10; // 局部變量
System.out.println("x = " + x);
}
int x = 100; // 全局變量
System.out.println("x = " + x);
}
}
把if取消,就成了普通代碼塊:
package com.wz.thisdemo;
public class TestDemo {
public static void main(String args[]) {
{ // 普通代碼塊
int x = 10; // 局部變量
System.out.println("x = " + x);
}
int x = 100; // 全局變量
System.out.println("x = " + x);
}
}
運行結果:
x = 10
x = 100
實際上、普通代碼塊可以防止在方法中編寫代碼過多引起變量重名,從而對一個方法中的代碼進行分割。
二、構造代碼塊
普通代碼塊是定義在方法之中的,而構造代碼塊是定義在類中的代碼塊。
package com.wz.thisdemo;
class Person {
public Person() {
System.out.println("構造方法。");
}
{ // 構造塊
System.out.println("構造塊。");
}
}
public class TestDemo {
public static void main(String args[]) {
new Person();
new Person();
new Person();
}
}
運行結果:
構造塊。
構造方法。
構造塊。
構造方法。
構造塊。
構造方法。
可以發現,構造塊先於構造方法執行,而且每當有一個新的實例化對象產生的時候,就會出現構造塊的執行。
從上面的運行結果可以看出在new一個對象的時候總是先執行構造代碼,再執行構造函數,但是有一點需要注意構造代碼不是在構造函數之前運行的,它是依託構造函數執行的。正是由於構造代碼塊有這幾個特性,所以它常用於如下場景:
(1)初始化實例變量
如果一個類中存在若干個構造函數,這些構造函數都需要對實例變量進行初始化,如果我們直接在構造函數中實例化,必定會產生很多重複代碼,繁瑣和可讀性差。這裏我們可以充分利用構造代碼塊來實現。這是利用編譯器會將構造代碼塊添加到每個構造函數中的特性。
(2)初始化實例環境
一個對象必須在適當的場景下才能存在,如果沒有適當的場景,則就需要在創建對象時創建此場景。我們可以利用構造代碼塊來創建此場景,尤其是該場景的創建過程較爲複雜。構造代碼會在構造函數之前執行。
上面兩個常用場景都充分利用構造代碼塊的特性,能夠很好的解決在實例化對象時構造函數比較難解決的問題,利用構造代碼不僅可以減少代碼量,同時也是程序的可讀性增強了。特別是當一個對象的創建過程比較複雜,需要實現一些複雜邏輯,這個時候如果在構造函數中實現邏輯,這是不推薦的,因爲我們提倡構造函數要儘可能的簡單易懂,所以我們可以使用構造代碼封裝這些邏輯實現部分。
三、靜態代碼塊
靜態塊也是定義在類中的,一個構造塊上使用了static關鍵字進行定義的話,那麼就表示靜態塊,它的主要目的就是對靜態屬性進行初始化。靜態塊要考慮兩種情況:
1、在非主類中使用
package com.wz.thisdemo;
class Person {
public Person() {
System.out.println("構造方法。");
}
{ // 構造塊
System.out.println("構造塊。");
}
static {
System.out.println("靜態塊。");
}
}
public class TestDemo {
public static void main(String args[]) {
new Person();
new Person();
new Person();
}
}
運行結果:
靜態塊。
構造塊。
構造方法。
構造塊。
構造方法。
構造塊。
構造方法。
可以發現,靜態塊優先於構造塊執行,而且不管有多少個實例化對象產生,靜態塊只調用一次。
2、在主類中定義的靜態塊
package com.wz.thisdemo;
public class TestDemo {
static {
System.out.println("靜態塊。");
}
public static void main(String args[]) {
System.out.println("Hello World .");
}
}
運行結果:
靜態塊。
Hello World .
在主類之中的靜態塊優先於主方法執行。
四、靜態代碼塊、構造代碼塊、構造函數執行順序
靜態代碼塊,靜態,其作用級別爲類,構造代碼塊、構造函數,構造,其作用級別爲對象。
1、 靜態代碼塊,它是隨着類的加載而被執行,只要類被加載了就會執行,而且只會加載一次,主要用於給類進行初始化。
2、 構造代碼塊,每創建一個對象時就會執行一次,且優先於構造函數,主要用於初始化不同對象共性的初始化內容和初始化實例環境。
3、 構造函數,每創建一個對象時就會執行一次。同時構造函數是給特定對象進行初始化,而構造代碼是給所有對象進行初始化,作用區域不同。
通過上面的分析,他們三者的執行順序爲:靜態代碼塊 > 構造代碼塊 > 構造函數。
五、同步代碼塊
使用 synchronized 關鍵字修飾,並使用“{}”括起來的代碼片段,它表示同一時間只能有一個線程進入到該方法塊中,是一種多線程保護機制。
(具體將會在多線程中講到)
參考: