关于java:new Class(…){{…}}初始化习语的含义

Meaning of new Class(…){{…}} initialization idiom

本问题已经有最佳答案,请猛点这里访问。

{{ ... }}块在以下代码中的含义是什么?

1
2
3
4
5
6
7
8
9
10
11
class X {

    private Y var1;

    private X() {
        Z context = new Z(new SystemThreadPool()) {{
            var1 = new Y();
        }};
    }

}


它被称为双花括号初始化。 (编辑:链接删除,存档在这里)

这意味着你正在创建一个匿名子类,双括号内的代码基本上是一个构造函数。它通常用于向集合添加内容,因为Java用于创建本质上是集合常量的语法有点尴尬。

所以你可能会这样做:

1
2
3
4
5
List<String> list = new ArrayList<String>() {{
  add("one");
  add("two");
  add("three");
}};

代替:

1
2
3
4
List<String> list = new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");

我实际上不喜欢这样,喜欢这样做:

1
List<String> list = Arrays.asList("one","two","three");

因此,在这种情况下它没有多大意义,而对于没有方便助手的地图来说也是如此。


"外部"括号表示您正在创建一个匿名子类,第二个大括号是对象初始化程序。初始化程序在类的构造函数之前运行,但是在任何super调用之后(因此也在任何超类初始化程序之后)。您也可以在非匿名类中使用初始化程序,如果您有多个不能相互调用的构造函数,或者需要比通常的字段初始化程序允许的更复杂的初始化的字段,这是启动final字段的便捷方式。

考虑这个课程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class X extends Y{
    private final int lulz;

    private static boolean someCondition(){...}
    private static boolean danger() throws SomeException { ... }
    public X(A a) throws SomeException {
        super(a);
        lulz = someCondition()? danger() : 0;
    }
    public X(B b) throws SomeException {
        super(b);
        lulz = someCondition()? danger() : 0;
    }
}

它可以改写为:

1
2
3
4
5
6
7
8
9
10
11
class X extends Y{
    private final int lulz;

    private static boolean someCondition(){...}
    private static boolean danger() throws SomeException { ... }
    { // initalizer -- might throw SomeException!
        lulz = someCondition()? danger() : 0;
    }
    public X(A a) throws SomeException { super(a); }
    public X(B b) throws SomeException { super(b); }
}

如果初始化程序可以抛出已检查的异常,则所有构造函数都必须声明它们可以抛出它。


您正在创建一个匿名类并使用类Instance初始化程序惯用法,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
class X {
    private Y var1;

    private X() {
        Z context = new Z(
               new SystemThreadPool()) {
                   {                        // This is the initialize idiom
                       var1 = new Y();      //
                   }                        //
               }
          );  // BTW you are missing")"
    }
}

如前面的答案所述,双花括号初始化是正确的。

它使用特定技术在Java中初始化实例成员。它是在类定义中定义一个共享代码块的简便方法,该代码块将在激活任何类构造函数时运行。

我正在添加描述它的官方Java文档的链接,以便更广泛地查看该主题。

从文档:

Initializer blocks for instance variables look just like static
initializer blocks, but without the static keyword:

{

1
// whatever code is needed for initialization goes here

}

The Java compiler copies initializer blocks into every constructor.
Therefore, this approach can be used to share a block of code between
multiple constructors.