【问题标题】:What is this constructor call with following double braces?这个带有以下双括号的构造函数调用是什么?
【发布时间】:2009-07-08 19:36:50
【问题描述】:

很遗憾,我已经有五年没有编写 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 ;) 但我不知道它为什么起作用。

【问题讨论】:

  • 当我第一次在 Usenet 上看到它时,我不得不看了一会儿才意识到发生了什么。一旦你知道它是什么,就很明显了。
  • 我不久前在 SO 上看到了这个巧妙的技巧,但我也看到了很多免责声明,说用它很容易破坏东西/不是很可靠。如果我要尝试使用它,我一定会考虑 A)我必须向每个人解释它以从那时起查看代码,并且 B)我必须做一些研究以了解使用此模式的所有含义。
  • 感谢大家快速而有帮助的回复!

标签: java syntax constructor anonymous-class


【解决方案1】:

这被称为double brace initialization

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

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

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

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

    【讨论】:

      【解决方案3】:
      MyTest tester = new MyTest() {{
         setName("John Johnson");
      }};
      

      相同
      MyTest tester = new MyTest();
      tester.setName("John Johnson");
      

      【讨论】:

      • 那些不一样。他们的成绩不是同一个班级。创建一个 MyTest 的实例。另一个创建 MyTest 的匿名子类的实例。如果您的 equals 方法如下所示: public boolean equals(Object other) { if( other.class != MyTest.class ) { return false; } //再做一些检查... } 那么它就不会认为它们是一样的。
      • @mangst 我认为您应该说它们“在大多数情况下功能等效”;你必须对这里有点迂腐——工程师的天性和所有......
      猜你喜欢
      • 2015-06-29
      • 2020-04-03
      • 2021-06-16
      • 1970-01-01
      • 2020-04-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-17
      相关资源
      最近更新 更多