原文地址:http://www.c2.com/cgi/wiki?DoubleBraceInitialization
這是我在JavaIdioms(http://www.c2.com/cgi/wiki?JavaIdioms)上看到一個Java使用技巧。使用Java這么多年了,也還是頭一次看到,還很實用。別看這小技巧好像很簡單,但保證你不會在任何一書Java教材上看到,因為它不是一個真正的語法規范,而是一個語法的用法變種。小技巧還蘊含著Java的深層知識,就是身經百戰的老手也不一定能說出其中奧妙。
翻譯正文:
由于Java語言的集合框架中(collections, 如list, map, set等)沒有提供任何簡便的語法結構,這使得在建立常量集合時的工作非常繁索。每次建立時我們都要做:
- 定義一個臨時的集合類變量
- 建立一個空集合的實例,然后賦值給變量
- 將數據放入集合中
- 最后將集合做為參數傳遞給方法
例如,要將一個Set變量傳給一個方法:
- Set<String> validCodes = new HashSet<String>();
- validCodes.add("XZ13s");
- validCodes.add("AB21/X");
- validCodes.add("YYLEX");
- validCodes.add("AR2D");
- removeProductsWithCodeIn(validCodes);
也可以用靜態初始的方法
- private static final Set<String> validCodes = new HashSet<String>();
- static {
- validCodes.add("XZ13s");
- validCodes.add("AB21/X");
- validCodes.add("YYLEX");
- validCodes.add("AR2D");
- }
其實,還有簡結的方法,我們可以用雙括弧語法(double-brace syntax)建立并初始化一個新的集合:
- private static final Set<String> VALID_CODES = new HashSet<String>() {{
- add("XZ13s");
- add("AB21/X");
- add("YYLEX");
- add("AR2D");
- }};
或者
- removeProductsWithCodeIn(new HashSet<String>() {{
- add("XZ13s");
- add("AB21/X");
- add("YYLEX");
- add("AR5E");
- }});
第一層括弧 實際是定義了一個內部匿名類 (Anonymous Inner Class),第二層括弧 實際上是一個實例初始化塊 (instance initializer block),這個塊在內部匿名類構造時被執行。這個塊之所以被叫做“實例初始化塊”是因為它們被定義在了一個類的實例范圍內。這和“靜態初始化塊 (static initialzer)”不同,因為這種塊在定義時在括弧前使用了static關鍵字,因此它的和類在同一個范圍內的,也就是說當類加載時就會被執行(更詳情,可參考Java語言規范http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6 )。實例初始化塊中可以使用其容器范圍內的所有方法及變量,但特別需要注意的是實例初始化塊是在構造器之前運行的。
這種方法只適用于不是final的類,因為final類是無法建立內部匿名子類,好在集合類都沒有這個限制。因此,這種方法還可以被用來初始化其它任何對象,比如一個GUI對象:
- add(new JPanel() {{
- setLayout(...);
- setBorder(...);
- add(new JLabel(...));
- add(new JSpinner(...));
- }});
這樣建立的內部匿名類的實例中包函它容器對像的引用。如果串行化(serialization)這個集合同時也會串行化它的內部類.