17

不幸的是,我已经有五年没有编写 Java 代码了,而且我完全不记得下面的代码是如何或为什么工作的。

我偶然发现了一个类似的例子并将其分解为这个。重点是注释下方的部分:我没有得到构造函数符号,后跟双括号中的块。不幸的是,我在 Java 文档中或使用 Google 找不到任何东西(我应该用什么词来搜索?)。

package syntaxtest;

public class Main {

    public static void main(String[] args) {

        // What kind of notation is this?
        MyTest tester = new MyTest() {{
            setName("John Johnson");
        }};

        System.out.println(tester.getName());
    }
}


class MyTest {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

所以这是我的问题:

  1. 这种表示法/语法是如何调用的?
  2. 我在哪里可以阅读有关它的一些文档?

我想/希望如果有人可以为我提供第一个问题的答案,我将能够自己回答第二个问题。

说清楚:我知道输出是John Johnson;) 但我不知道它为什么起作用。

4

3 回答 3

21

这称为双括号初始化

第一个大括号创建了一个新的 AnonymousInnerClass,第二个大括号声明了一个实例初始化块,该块在实例化匿名内部类时运行。这种类型的初始化程序块正式称为“实例初始化程序”,因为它是在类的实例范围内声明的——“静态初始化程序”是一个相关概念,其中关键字 static 放在开始块的大括号之前,并且一旦类加载器完成加载类,它就会在类级别执行(在 http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6中指定) 初始化程序块可以使用包含范围内可用的任何方法、字段和最终变量,但必须警惕初始化程序在构造函数之前运行的事实。

这仅适用于非最终类,因为它创建了一个匿名子类。

于 2009-07-08T19:39:59.500 回答
16

让我们对代码进行一些不同的布局:

MyTest tester = new MyTest() {
  {
    setName("John Johnson");
  }
};

您在此处看到的称为双括号初始化。您有一个 class 的匿名内部子类MyTest,以及一个初始化程序块,它是一个包含在构造对象时运行的代码的块。

通常,您会将此类代码放在构造函数中,但由于匿名内部类不能具有构造函数,因此这是保证代码按预期运行的唯一方法。

话虽如此,这样做有点难看。有更好的方法。但是,我有时会自己使用它,通常使用以下习惯用法来创建不可变映射:

final Map<String, Integer> textToInt = Collections.unmodifiableMap(new HashMap<String, Integer>() {{
    put("one", 1);
    put("two", 2);
    // etc
}});

它创建了一个新映射,覆盖它,在初始化块中向它添加一些值,并将其包装在一个不可修改的映射中。

于 2009-07-08T19:40:36.503 回答
-5
MyTest tester = new MyTest() {{
   setName("John Johnson");
}};

是相同的

MyTest tester = new MyTest();
tester.setName("John Johnson");
于 2009-07-08T20:00:29.677 回答