Java中的双括号初始化是什么?

Java中的双括号初始化语法()是什么?{{ ... }}


答案 1

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

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

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


答案 2

每当有人使用双括号初始化时,一只小猫就会被杀。

除了语法相当不寻常并且不是真正的习语(当然,味道是值得商榷的)之外,你不必要地在你的应用程序中造成了两个重大问题,我最近刚刚在这里更详细地写了两个博客。

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;
    }
}

返回的现在将包含对封闭实例 的引用。您可能不想冒以下风险:MapReallyHeavyObject

Memory Leak Right Here

图片来自 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"); }};

有些人可能会发现这在语法上是刺激性的。