我有两个问题。首先,请考虑以下代码。
public class Test{
private static final List<String> var = new ArrayList<String>() {{
add("A");
add("B");
System.out.println("INNER : " + var);
}};
public static void main(String... args){
System.out.println("OUTER : " + var);
}
}
当我运行这段代码时,它会在输出下方显示
INNER : null
OUTER : [A, B]
任何人都可以详细说明为什么INNER
为空并且在collection
上恰好加上“ A”和“ B”时执行流吗?
第二,我在上面的代码中做了一些更改,并修改为下面的代码(只需将add方法放在第一个括号内)
public class Test{
private static final List<String> var = new ArrayList<String>() {
public boolean add(String e) {
add("A");
add("B");
System.out.println("INNER : " + var); return true;
};
};
public static void main(String... args){
System.out.println("OUTER : "+var);
}
}
运行上面的代码后,我得到的结果是下面的
OUTER : []
查看此内容后,我对正在发生的事情一无所知。 INNER
去了哪里?为什么不打印?不叫吗?
答案 0 :(得分:13)
因为在{em>之前匿名类的实例引用已分配给ArrayList
,所以执行了var
匿名类的初始化程序块。
由于您从不调用add(String e)
方法,因此不会执行该代码。如果这样做的话,将导致StackOverflowError
,因为add("A")
现在是递归调用。
答案 1 :(得分:5)
您创建的对象尚未在初始化过程中分配给var
,请尝试以下操作:
private static final List<String> var = new ArrayList<String>() {{
add("A");
add("B");
System.out.println("THIS : " + this); // THIS : [A, B]
System.out.println("INNER : " + var); // INNER : null
}};
您只需覆盖add
的{{1}}方法,就更麻烦了。它的工作原理是:
ArrayList
答案 2 :(得分:2)
在代码段1中,您正在使用双括号初始化将项目添加到数组列表中。它基本上是一个带有实例初始化器的匿名内部类。由于在构造对象之前先打印var
,所以它是null
。
在第二个代码段中,您将创建一个ArrayList的匿名类,该类提供add
方法的实现。但是没有人调用ArrayList对象上的add
方法。
编辑:Andreas@提出的要点-即使您调用add方法,也会导致无限递归调用,从而产生StackOverflowError
。
参考:
答案 3 :(得分:1)
在第一个代码中,在添加变量并在实例初始化器内打印列表之前,先打印变量,然后返回其构造函数。
因此它只能打印null
。
在第二个代码中,您重写add()
以添加硬编码元素,但是从未在创建的实例上调用add()
。因此add()
不会打印任何内容,并且List实例中也不会添加任何内容。
要在列表中添加元素,通常需要在列表引用上调用add()
,例如:
List<String> list = new ArrayList<>();
list.add("element A");
list.add("element B");
您不会为此要求创建匿名类。
如果您想使用更简单的语法,您仍然可以执行以下操作:
List<String> list = new ArrayList<>(Arrays.asList("element A", "element B"));