繁体   English   中英

使用包括块初始化程序的匿名类初始化静态ArrayList字段

[英]initializing static ArrayList field using anonymous class including a block initializer

我在玩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也通过包含块初始化程序的匿名类进行初始化。 但是问题是我们在“ this”引用中添加了“ John”并打印了NAMES,因此显示为空。 如果我们以这种方式进行更改,则代码将正确运行:

System.out.println(this);

代替:

System.out.println(NAMES);

为什么会这样呢?

当您使用“双括号”初始化时,您将使用外部括号创建ArrayList的匿名子类,而内部一对括号则代表实例初始化程序,在此您调用add并打印出NAMES 但是在您构建ArrayList的那一刻,尚未完成ArrayList构建,并且尚未将其分配给NAMES 变量NAMES的默认值仍为null

尽管语法看起来很漂亮,但仅仅为了易于初始化,创建匿名子类通常不值得。

相反,如果必须静态完成此操作,则将列表内容的初始化移动到静态初始值设定项块,以便在引用时已经对NAMES进行了初始化。

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

本质上可以认为是

new MyList();

其中MyList定义为:

class MyList extends ArrayList<String> {
    public MyList() {
        super();
        add("John");
        System.out.println(NAMES);
    }
}

事件的顺序为:

  1. 调用构造函数
  2. 将构造函数返回的对象分配给名为“ NAMES”的静态字段

所以,因为System.out.println发生在构造函数中 ,有称这NAMES意味着转让尚未发生并不起作用,但称这是this是有效的。


您应该选择以下其中一种(取决于Java版本和元素数):

private static final List<String> NAMES = Arrays.asList("John");
private static final List<String> NAMES = List.of("John");
private static final List<String> NAMES = Collections.singletonList("John");

随后是用于打印的静态块:

static {
    System.out.println(NAMES);
}

List NAMES尚未完成初始化的原因,因此NAMES null ,但在使用this关键字时得到[John] ,如果在main打印,则将根据需要生成输出。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM