偶然見到一種初始化方式,感到十分新奇:
//新建一個列表並賦初值A、B、C
ArrayList list = new ArrayList() {{
add("A");
add("B");
add("C");
}};
還有其他集合比如HashMap的初始化:
Map map = new HashMap() {{
put("Name", "Unmi");
put("QQ", "1125535");
}};
這種方式比起先new出對象,再一條條add,顯得更加簡潔和優雅。一開始沒想通什么原理,后來查了一下才知道這種方法被稱為雙大括號初始化(double brace initialization)或者匿名內部類初始化法,實際上是一種取巧的方式。
理解:
這里以ArrayList的例子解釋,首先第一層花括號定義了一個繼承於ArrayList的匿名內部類 (Anonymous Inner Class):
//定義了一個繼承於ArrayList的類,它沒有名字
new ArrayList(){
//在這里對這個類進行具體定義
};
第二層花括號實際上是這個匿名內部類實例初始化塊 (Instance Initializer Block)(或稱為非靜態初始化塊):
new ArrayList(){
{
//這里是實例初始化塊,可以直接調用父類的非私有方法或訪問非私有成員
}
};
我們通過new得到這個ArrayList的子類的實例並向上轉型為ArrayList的引用:
ArrayList list = new ArrayList() {{}};
我們得到的實際上是一個ArrayList的子類的引用,雖然這個子類相比ArrayList並沒有任何功能上的改變。
可以認為這是個本身裝有數據的子類(因為它的數據來自於自身的初始化),而不是取得引用后再賦值。
下面自定義一個類並使用這種方式初始化:
class Person{
protected String name;
protected int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
...
public static void main(String[] args) {
Person p = new Person(){
{
name = "xiaoming"; //或者調用setName()
age = 3; //或者setAge()
}
};
System.out.println(p.getName() + p.getAge());
}
注意:
(1)這種方法一定程度上使代碼更簡潔,但同時可能降低可讀性;還可能會造成內存泄露,在序列化時可能也會出現一些問題(未測試)。
(2)當我們想構造一個數組列表,並將它傳遞到一個方法時,最初的寫法如下:
ArrayList friends=new ArrayList<>();
friends.add("tom");
friends.add("lin");
invite(friends);
如果不想要寫這個數組列表,可將其作為一個匿名列表,通過雙括號的方式為列表添加元素,這樣代碼更為簡潔。
invite(new ArrayList ()
{
{
add("tom");
add("lin");
}
})
外層“{}”創建了ArrayLIst的一個匿名子類,內層“{}”創建了一個對象構造塊。