什么是双大括号初始化语法({{…}})在Java?
当前回答
双大括号初始化创建一个从指定类派生的匿名类(外大括号),并在该类中提供一个初始化程序块(内大括号)。如。
new ArrayList<Integer>() {{
add(1);
add(2);
}};
注意,使用这种双大括号初始化的效果是创建匿名的内部类。创建的类有一个隐式this指针指向周围的外部类。虽然通常不是问题,但在某些情况下,例如序列化或垃圾收集时,它可能会导致痛苦,值得注意这一点。
其他回答
第一个大括号创建了一个新的匿名内部类。 第二组大括号创建了一个实例初始化器,类似于Class中的static block。
例如:
public class TestHashMap {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<String,String>(){
{
put("1", "ONE");
}{
put("2", "TWO");
}{
put("3", "THREE");
}
};
Set<String> keySet = map.keySet();
for (String string : keySet) {
System.out.println(string+" ->"+map.get(string));
}
}
}
它是如何工作的
第一个大括号创建了一个新的匿名内部类。这些内部类能够访问它们的父类的行为。因此,在本例中,我们实际上是在创建HashSet类的子类,因此这个内部类能够使用put()方法。
第二组大括号只是实例初始化器。如果你还记得核心java概念,那么你可以很容易地将实例初始化器块与静态初始化器关联起来,因为类似struct的大括号。唯一的区别是静态初始化器添加了static关键字,并且只运行一次;不管你创建了多少个对象。
more
这似乎与flash和vbscript中流行的with关键字相同。这是一种改变事物的方法,仅此而已。
关于双大括号初始化的有趣应用,请参阅这里的Dwemthy 's Array in Java。
摘录
private static class IndustrialRaverMonkey
extends Creature.Base {{
life = 46;
strength = 35;
charisma = 91;
weapon = 2;
}}
private static class DwarvenAngel
extends Creature.Base {{
life = 540;
strength = 6;
charisma = 144;
weapon = 50;
}}
现在,准备好迎接香肠味和培根味的大战吧!
每当有人使用双大括号初始化时,就会有一只小猫被杀死。
除了语法相当不寻常且不是真正的惯用(当然,品味是有争议的)之外,您还不必要地在应用程序中创建了两个重大问题,我最近在博客中对此进行了更详细的讨论。
1. 你创建了太多的匿名类
每次使用双大括号初始化都会创建一个新类。例如这个例子:
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};
... 将产生这些类:
Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class
这对您的类加载器来说是相当大的开销——毫无意义!当然,如果你只做一次,就不会花费太多初始化时间。但是如果你在整个企业应用程序中做了20000次这样的事情……那么多内存只是为了一点“语法糖”?
2. 您可能会造成内存泄漏!
如果您使用上述代码并从一个方法返回该映射,那么该方法的调用者可能会毫无疑问地持有无法被垃圾收集的非常重的资源。考虑下面的例子:
public class ReallyHeavyObject {
// Just to illustrate...
private int[] tonsOfValues;
private Resource[] tonsOfResources;
// This method almost does nothing
public Map quickHarmlessMethod() {
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};
return source;
}
}
返回的Map现在将包含对ReallyHeavyObject的封装实例的引用。你可能不想冒这个险:
图片来自http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/
3.你可以假装Java有地图字面量
为了回答你的实际问题,人们一直在使用这种语法来假装Java有类似map字面量的东西,类似于现有的数组字面量:
String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};
有些人可能会觉得这在语法上很刺激。
你是说像这样的事?
List<String> blah = new ArrayList<String>(){{add("asdfa");add("bbb");}};
这是在创建时初始化数组列表(hack)
推荐文章
- codestyle;把javadoc放在注释之前还是之后?
- 如何在Spring中定义List bean ?
- 将Set<T>转换为List<T>的最简洁的方法
- 在JavaScript中,什么相当于Java的Thread.sleep() ?
- 使用Java重命名文件
- URL从Java中的类路径加载资源
- .toArray(new MyClass[0]) or .toArray(new MyClass[myList.size()])?
- Hibernate中不同的保存方法之间有什么区别?
- Java 8流和数组操作
- Java Regex捕获组
- Openssl不被视为内部或外部命令
- 如何添加自定义方法到Spring Data JPA
- 如何在Ubuntu中设置Java环境路径
- 无法执行dex:在Eclipse中超过GC开销限制
- 有人能解释一下JPA和Hibernate中的mappedBy吗?