双括号初始化集合
对于set、list、map集合,可以使用如下的方式进行初始化:
Set<String> set1 = new HashSet<String>(){{
add("a");
add("b");
}};
List<String> list1 = new LinkedList<String>() {{
add("a");
add("b");
add("c");
}};
Map<String,String> map1 = new HashMap<String,String>(){{
put("a","a");
put("b","b");
put("c","c");
}};
这里利用了内部类语法,这种方式比先new出对象然后再进行依次add要方便、简洁许多。该方法称之为“双括号初始化”(double brace initialization)。
1、语法解读:
显然这是在HashMap的构造器中写了一个匿名内部类,这个匿名内部类含有一个实例初始化块,初始化块的内容是三个add()函数,向被初始化的this指向的HashMap中添加了三个元素。
2、性能问题:
利用双大括号初始化集合从效率上来说可能不如标准的集合初始化步骤。原因在于使用双大括号初始化会导致内部类文件的产生,而这个过程就会影响代码的执行效率。
假设有一个Test1类,里面有1000个list,都是使用双括号初始化,编译后如下:
Test1$1.class
Test1$2.class
...
Test1$1000.class
二、其他初始化集合方式
下面是集中常见的集合初始化写法。
1、ImmutableList.of:
guava提供的一种不可变集合的初始化,该方法返回一个不可变的集合。示例:
List<String> places = ImmutableList.of("Buenos Aires", "Córdoba", "La Plata");
places.add("test");//报错:java.lang.UnsupportedOperationException
2、Arrays.asList():
该方法返回的是一个list视图,不能对其进行修改。示例:
List<String> places = Arrays.asList("Buenos Aires", "Córdoba", "La Plata");
places.add("test");//报错:java.lang.UnsupportedOperationException
3、new ArrayList<String>(Arrays.asList()):
对上面的一种改进,推荐使用这种方法。示例:
List<String> strings = new ArrayList<String>(Arrays.asList("foo", "bar", "baz"));
strings.add("test");
三、关于匿名内部类
匿名内部类也就是没有名字的内部类。正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写,但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口。
1、不使用匿名内部类来实现抽象方法:
abstract class Person {
public abstract void eat();
}
class Child extends Person {
public void eat() {
System.out.println("eat something");
}
}
public class Demo {
public static void main(String[] args) {
Person p = new Child();
p.eat();
}
}
2、使用匿名内部类实现抽象方法:
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
这种写法比较简洁。此外,匿名内部类还能用于接口上,例如:
interface Person {
public void eat();
}
public class Demo {
public static void main(String[] args) {
Person p = new Person() {
public void eat() {
System.out.println("eat something");
}
};
p.eat();
}
}
由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现。最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口。
Thread t = new Thread() {
@Override
public void run() {
System.out.println("thread...");
}
};
t.start();
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Runnable...");
}
};
new Thread(r).start();