Java双括号初始化总是有效吗?

我知道这个代码:

Set<String> set = new HashSet<String>() {{
  add("test1");
  add("test2");
}};

真的是:

Set<String> set = new HashSet<String>() {
  {//initializer
    add("test1");
    add("test2");
  }
};

初始值设定项块在构造函数块之前执行。在上面的示例中,add(“test1”) 在执行构造函数之前被调用。构造函数可能正在初始化许多实例字段,以便此类可以正常工作。我想知道为什么在构造函数之前调用.add()会起作用?是否有任何情况会导致问题?


答案 1

您遗漏了一个细节来解释这一点。

首先,让我们回顾一下初始化过程的步骤 3 到 5(总结):

3. 超类构造函数称为
4。实例初始值设定项称为
5。构造函数的主体称为

您遗漏的细节是,您的表达式不仅仅是创建类的新实例,实际上是在创建 匿名子类 的新实例。(我相信这在15.9.1节中指定。HashSetHashSet

由于您没有声明构造函数,因此使用默认构造函数。但在此之前,超类的构造器已经完成了。HashSet

因此,总而言之,构造函数在初始值设定项块运行之前完成。HashSet


答案 2

这个假设是错误的:

初始值设定项块在构造函数块之前执行。

因为在此特定情况下,初始值设定项块是构造函数块的一部分

文档明确指出

Java 编译器将初始值设定项块复制到每个构造函数中。因此,此方法可用于在多个构造函数之间共享一个代码块。

我认为您与静态初始值设定项混淆了。


推荐