構造代碼塊(Instance Initializer)在每個建構子執行前自動執行,編譯器會將其複製到每個建構子開頭。
public class Client36 {
{ // 構造代碼塊
System.out.println("執行構造代碼塊");
}
public Client36() { System.out.println("無參建構子"); }
public Client36(String name) { System.out.println("有參建構子:" + name); }
}
// 等價於編譯器生成:
// public Client36() { System.out.println("執行構造代碼塊"); System.out.println("無參建構子"); }
// public Client36(String name) { System.out.println("執行構造代碼塊"); System.out.println("有參建構子:" + name); }
適用場景:多建構子共享初始化邏輯(如資源獲取、驗證、日誌、計數器)。
當建構子使用 this(...) 呼叫另一建構子時,編譯器不會重複插入構造代碼塊,避免雙重執行:
class Student {
private static int count = 0;
{ count++; } // 構造代碼塊
public Student() {}
public Student(String name) { this(); } // 呼叫無參建構子
public Student(int age) {} // 不呼叫其他建構子
}
new Student(); // count=1
new Student("Tom"); // count=2 (this() 不觸發第二次構造塊)
new Student(18); // count=3
注意:super(...) 不會抑制構造代碼塊,父類構造塊在 super() 後執行,子類構造塊在 super() 後、子類建構子本體前執行。
static class Inner 不持有外部類引用,獨立存在,優點:
Person.Home 明確表達「人的家庭資訊」強關聯。new Person.Home("北京", "010") 符合領域語言。public class Person {
private String name;
private Home home;
public static class Home { // 靜態內部類
private String address;
private String tel;
public Home(String address, String tel) { ... }
// getter/setter
}
// getter/setter
}
// 使用
Person p = new Person("張三");
p.setHome(new Person.Home("北京", "010"));
關鍵區別:靜態內部類 ≒ 頂層類(只是命名空間不同);非靜態內部類持有外部類引用,生命週期綁定。
new ArrayList() {{ add("A"); }} 實為:
ArrayList 的匿名子類。List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>() {}; // 匿名子類,無初始化塊
List<String> list3 = new ArrayList<>() {{ add("A"); }}; // 匿名子類 + 實例初始化塊
List<String> list4 = new ArrayList<>() {{ add("A"); } { add("B"); }}; // 多個初始化塊,依序執行
System.out.println(list1.getClass() == list2.getClass()); // false
System.out.println(list2.getClass() == list3.getClass()); // false
System.out.println(list3.getClass() == list4.getClass()); // false
每個 {} 產生獨立匿名類,類別身份不同。
匿名類無名稱,無法宣告建構子,但實例初始化塊可接收外部建構子參數:
Calculator c = new Calculator(10, 5) { // 呼叫父類 Calculator(int, int)
{ setOperator(Ops.ADD); } // 實例初始化塊 = 匿名類「建構子」
};
System.out.println(c.getResult()); // 15
編譯器生成等價碼:
class AnonCalc extends Calculator {
{ setOperator(Ops.ADD); }
public AnonCalc(int i, int j) { super(i, j); } // 自動呼叫父類同參數建構子
}
關鍵差異:普通類建構子預設呼叫 super()(無參),匿名類自動匹配父類相同參數列表的建構子。
| 特性 | 構造代碼塊 | 靜態內部類 | 匿名類 |
|---|---|---|---|
| 執行時機 | 每次 new 實例時,建構子前 | 類別載入時 | new 表達式執行時 |
| 可存取外部 this | 是 | 否 | 是 |
| 可定義建構子 | 否 | 是 | 否(用初始化塊代替) |
| 主要用途 | 共享實例初始化邏輯 | 封裝強關聯領域概念 | 就地實作介面/擴充類、雙大括號初始化 |
| 序列化風險 | 低 | 低 | 高(合成類名不穩定) |
List.of()、Stream.of()、Builder 模式或工具方法。