Java集合的双大括号初始化原理
使用两个大括号进行初始化
如ArrayList
List<String> list = new ArrayList<String>() {{
add("Hello");
add("World!");
}};
HashMap
Map<String, Object> map = new HashMap<String, Object>() {
{
put("name", "Tom");
put("age", 10);
}
};
这种方法被称为双大括号初始化(double brace initialization)或者匿名内部类初始化法
原理
第一层花括号定义了一个继承于ArrayList的匿名内部类 (Anonymous Inner Class):
//定义了一个继承于ArrayList的匿名内部类
new ArrayList<String>(){
};
第二层花括号是这个匿名内部类实例初始化块 (Instance Initializer Block)(或称为非静态初始化块):
new ArrayList<String>(){
{
//这里是实例初始化块,可以直接调用父类的非私有方法或访问非私有成员
}
};
我们通过new得到ArrayList的子类的实例化,然后上转型为ArrayList的引用
ArrayList<String> list = new ArrayList<String>() {{}};
上转型下转型:https://blog.csdn.net/qq_46186167/article/details/118788706
效率问题
Java 必知必会 第 18 篇 efficiency-of-java-double-brace-initialization
Double Brace Initialization是一个带有实例初始化块的匿名内部类。这就意味着每一个新的类的产生都会执行一次实例块,这样的目的通常是为了创建一个简单的对象。
java虚拟机在使用类之前需要去读取其classes信息,然后执行字节码校验等流程。所以为了保存这些class文件,所需要的磁盘空间会增大。
这个可以说是Double Brace Initialization的开销。所以尽量不要过分使用。
实践
做一个简单的试验:创建1000个带着"Hello"
和"World!"
元素的ArrayList
- 方法1:Double Brace Initialization
class Test1 {
public static void main(String[] s) {
long st = System.currentTimeMillis();
List<String> l0 = new ArrayList<String>() {{
add("Hello");
add("World!");
}};
List<String> l1 = new ArrayList<String>() {{
add("Hello");
add("World!");
}};
/* snip */
List<String> l999 = new ArrayList<String>() {{
add("Hello");
add("World!");
}};
System.out.println(System.currentTimeMillis() - st);
}
}
- 方法2:初始化
ArrayList
并调用add
方法
class Test2 {
public static void main(String[] s) {
long st = System.currentTimeMillis();
List<String> l0 = new ArrayList<String>();
l0.add("Hello");
l0.add("World!");
List<String> l1 = new ArrayList<String>();
l1.add("Hello");
l1.add("World!");
/* snip */
List<String> l999 = new ArrayList<String>();
l999.add("Hello");
l999.add("World!");
System.out.println(System.currentTimeMillis() - st);
}
}
然后得出了下面的测试时间:
Test1 Times (ms) Test2 Times (ms)
---------------- ----------------
187 0
203 0
203 0
188 0
188 0
187 0
203 0
188 0
188 0
203 0
从上面我们可以看到,Double Brace Initialization平均时间花费了190ms左右。
同时,另外一种方法平均只用了0ms。
所以,在第一个方法测试程序中,即Double Brace Initialization产生了1000个class文件。