首页 > 解决方案 > 使用包括块初始化程序的匿名类初始化静态 ArrayList 字段

问题描述

我在玩 javaDeathmatch 游戏,遇到了一个我无法回答的问题。你能帮助我吗?

public class DeathMatch {
    private static final List<String> NAMES = new ArrayList<>() {{
        add("John");
        System.out.println(NAMES);
    }};

    public static void main(String[] args) {
        //Nothing in particular
    }
}

在这种情况下,当我们运行 JVM 时,将加载该类,首先创建并初始化其静态成员“NAMES”。ArrayList 也通过包括块初始化程序的匿名类进行初始化。但问题是我们将“John”添加到“this”引用并打印 NAMES,因此它显示为 null。如果我们以这种方式进行更改,代码将正确运行:

System.out.println(this);

代替:

System.out.println(NAMES);

为什么会这样?

标签: javaarraylistinitialization

解决方案


当您使用“双大括号”初始化时,您将创建一个ArrayList带有外大括号的匿名子类,而内大括号对代表实例初始化程序,您将在其中调用add并打印NAMES. 但是在您构建 时ArrayListArrayList尚未完成构建,并且尚未分配给它NAMES。该变量NAMES仍然具有其默认值null

虽然语法可能看起来很漂亮,但通常不值得仅仅为了便于初始化而创建匿名子类。

相反,如果这必须静态完成,则将列表内容的初始化移动到静态初始化程序块,以便NAMES在引用时已经初始化。

private static final List<String> NAMES = new ArrayList<String>();
static {
    NAMES.add("John");
    System.out.println(NAMES);
}

推荐阅读