初見 Double Brace Initialization 時,許多人會以為 Java 有了特殊的集合字面值語法:
Map map = new HashMap() {{
put("Name", "Unmi");
put("QQ", "1125535");
}};
List stooges = new ArrayList() {{
add("Larry"); add("Moe"); add("Curly");
}};
看起來比分行寫優雅許多。但格式化後(Ctrl+Shift+F)真相大白:
Map map = new HashMap() {
{
put("Name", "Unmi");
put("QQ", "1125535");
}
};
本質:匿名內部類 + 實例初始化塊。
final class com.unmi.TestDoubleBrace$1 extends java.util.HashMap {
com.unmi.TestDoubleBrace$1();
Code:
0: aload_0
1: invokespecial #8 // HashMap.
4: aload_0
5: ldc #10 // "Name"
7: ldc #12 // "Unmi"
9: invokevirtual #14 // put
12: pop
13: aload_0
14: ldc #18 // "QQ"
16: ldc #20 // "1125535"
18: invokevirtual #14 // put
21: pop
22: return
}
TestDoubleBrace$1.class → 每次使用都會產生一個新的匿名子類別<init> 中執行| 問題 | 影響 |
|---|---|
| 產生額外類別檔案 | 類別載入開銷、PermGen/Metaspace 壓力、JAR 體積膨脹 |
| 破壞類別結構 | 邏輯上是 HashMap,實際是匿名子類,instanceof/序列化/反射可能出現異常行為 |
| 持有外部類別隱含引用 | 若在非 static 內容使用,匿名類別隱含持有 this 參考 → 記憶體洩漏風險 |
| 序列化相容性極差 | serialVersionUID 隨編譯器生成,跨 JVM/版本極易 InvalidClassException |
| 框架相容性陷阱 | 如 XStream、Jackson、Hibernate 依賴具體類別型別,匿名子類會導致轉換失敗或忽略配置 |