什么是Java中的Double Brace初始化?

问题

Java中的Double Brace初始化语法({{ ... }})是什么?


#1 热门回答(208 赞)

每当有人使用双支撑初始化时,一只小猫就会被杀死。
除了语法相当不寻常并且不是真正的惯用语(当然味道有争议)之外,你在应用程序中不必要地创建了两个重要问题,which I've just recently blogged about in more detail here

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

这对你的类加载器来说是一个相当大的开销 - 什么都没有!当然,如果你这样做一次,它将不需要太多的初始化时间。但是,如果你在整个企业应用程序中执行此操作20'000次...所有堆内存只是为了一点"语法糖"?

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的引用。你可能不想冒这个风险:

Memory Leak Right Here
图像来自http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/

3.你可以假装Java有 Map 文字

为了回答你的实际问题,人们一直在使用这种语法假装Java有类似于现有数组文字的 Map 文字:

String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};

有些人可能会发现这种语法刺激。


#2 热门回答(203 赞)

双括号初始化创建一个从指定类(theouterbraces)派生的匿名类,并在该类中提供初始化块(theinnerbraces)。例如

new ArrayList<Integer>() {{
   add(1);
   add(2);
}};

请注意,使用此双括号初始化的效果是你正在创建匿名内部类。创建的类具有对周围外部类的隐式this指针。虽然通常不是问题,但在某些情况下会导致悲伤,例如:在序列化或垃圾收集时,值得注意这一点。


#3 热门回答(34 赞)

  • 第一个大括号创建一个新的匿名内部类。
  • 第二组大括号创建一个实例初始值设定项,如Class中的静态块。
    例如:
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));
        }
    }

}

工作原理

First brace创建一个新的匿名内部类。这些内部类能够访问其父类的行为。所以,在我们的例子中,我们实际上是在创建一个HashSet类的子类,所以这个内部类能够使用add()方法。

And第二组大括号只是实例初始化器。如果你提醒核心Java概念,那么你可以轻松地将实例初始化程序块与静态初始化程序相关联,因为类似于大写字母结构。唯一的区别是静态初始化程序添加了静态关键字,并且只运行一次;无论你创建多少个对象。
more