我正在向 ArrayList 添加三个不同的对象,但该列表包含我添加的最后一个对象的三个副本。
例如:
for (Foo f : list) {
System.out.println(f.getValue());
}
预期:
0
1
2
实际:
2
2
2
我犯了什么错误?
注意:这是针对本网站上出现的众多类似问题的规范问答。
最佳答案
此问题有两个典型原因:
列表中存储的对象使用的静态字段
意外地将相同对象添加到列表中
静态字段
如果列表中的对象将数据存储在静态字段中,则列表中的每个对象将看起来相同,因为它们保存相同的值。考虑下面的类:
public class Foo {
private static int value;
// ^^^^^^------------ - Here's the problem!
public Foo(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
在该示例中,只有一个 int 值
在 Foo
的所有实例之间共享,因为它被声明为 static
。 (请参阅 "Understanding Class Members" 教程。)
如果使用下面的代码将多个 Foo
对象添加到列表中,则每个实例都会通过调用 getValue()
返回 3
:
for (int i = 0; i < 4; i++) {
list.add(new Foo(i));
}
解决方案很简单 - 不要对类中的字段使用 static
关键字,除非您确实希望在该类的每个实例之间共享值。
添加相同对象
如果将临时变量添加到列表中,则每次循环时都必须创建要添加的对象的新实例。考虑以下错误的代码片段:
List<Foo> list = new ArrayList<Foo>();
Foo tmp = new Foo();
for (int i = 0; i < 3; i++) {
tmp.setValue(i);
list.add(tmp);
}
这里,tmp
对象是在循环外部构造的。结果,相同的对象实例被添加到列表中三次。该实例将保存值 2
,因为这是上次调用 setValue()
期间传递的值。
要解决此问题,只需将对象构造移动到循环内即可:
List<Foo> list = new ArrayList<Foo>();
for (int i = 0; i < 3; i++) {
Foo tmp = new Foo(); // <-- fresh instance!
tmp.setValue(i);
list.add(tmp);
}
关于java - 为什么我的 ArrayList 包含添加到列表中的最后一项的 N 个副本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40132040/