什么是Java雙大括號初始化膘掰?
通常情況下章姓,初始化Java集合并向其中添加幾個元素的步驟如下:
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
或者我們可以在靜態(tài)初始化塊中向作為靜態(tài)變量的集合添加元素:
private static final Set<Integer> set = new HashSet<>();
static {
set.add(1);
set.add(2);
set.add(3);
}
從語法上來看,這樣的初始化方法雖然格式清晰明了,但語法上略顯冗余凡伊。事實上零渐,Java允許一種精簡的雙大括號初始化方法:
Set<Integer> set = new HashSet<Integer>() {{
add(1);
add(2);
add(3);
}};
或是在接收集合作為輸入的函數(shù)中直接初始化:
someFunction(new HashSet<Integer>() {{
add(1);
add(2);
add(3);
}}
);
語法解讀
事實上窗声,如下雙大括號初始化Set
的代碼
Set<Integer> set = new HashSet<Integer>() {{
add(1);
add(2);
add(3);
}};
是以下這段代碼的改寫:
Set<Integer> set = new HashSet<Integer>() {
{
add(1);
add(2);
add(3);
}
};
改寫之后的代碼就非常容易理解了辜纲。顯然這是在HashSet的構(gòu)造器中寫了一個匿名內(nèi)部類笨觅,這個匿名內(nèi)部類含有一個實例初始化塊,初始化塊的內(nèi)容是三個add()
函數(shù)耕腾,向被初始化的this
指向的HashSet
中添加了三個元素见剩。
效率問題和產(chǎn)生的.class
文件結(jié)構(gòu)
利用雙大括號初始化集合從效率上來說可能不如標(biāo)準(zhǔn)的集合初始化步驟。原因在于使用雙大括號初始化會導(dǎo)致內(nèi)部類文件的產(chǎn)生扫俺,而這個過程就會影響代碼的執(zhí)行效率苍苞。
例如如下代碼:
// Double brace initialization
class Test1 {
public static void main(String[] args) {
long st = System.currentTimeMillis();
Set<Integer> set0 = new HashSet<Integer>() {{
add(1);
add(2);
}};
Set<Integer> set1 = new HashSet<Integer>() {{
add(1);
add(2);
}};
/* snip */
Set<Integer> set999 = new HashSet<Integer>() {{
add(1);
add(2);
}};
System.out.println(System.currentTimeMillis() - st);
}
}
// Normal initialization
class Test2 {
public static void main(String[] s) {
long st = System.currentTimeMillis();
Set<Integer> set0 = new HashSet<Integer>();
set0.add(1);
set0.add(2);
Set<Integer> set1 = new HashSet<Integer>();
set1.add(1);
set1.add(2);
/* snip */
Set<Integer> set999 = new HashSet<Integer>();
set999.add(1);
set999.add(2);
System.out.println(System.currentTimeMillis() - st);
}
}
用javac
命令compile第一段代碼會產(chǎn)生1000個.class
文件,如下所示:
Test1$1.class
Test1$2.class
...
Test1$1000.class
同時從程序輸出的運(yùn)行時間來看狼纬, 雙大括號初始化也顯著慢于普通初始化的代碼羹呵。差值大約在100ms左右。