Java 为什么我的ArrayList包含添加到列表中的最后一项的N个副本?
我正在向ArrayList添加三个不同的对象,但该列表包含我添加的最后一个对象的三个副本 例如:Java 为什么我的ArrayList包含添加到列表中的最后一项的N个副本?,java,list,arraylist,static,Java,List,Arraylist,Static,我正在向ArrayList添加三个不同的对象,但该列表包含我添加的最后一个对象的三个副本 例如: for (Foo f : list) { System.out.println(f.getValue()); } 预期: 0 1 2 实际: 2 2 2 我犯了什么错误 注:这是针对本网站上出现的许多类似问题的规范问答。此问题有两个典型原因: 存储在列表中的对象使用的静态字段 意外地将同一对象添加到列表中 静态场 如果列表中的对象将数据存储在静态字段中,则列表中的每个对象都
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
。(请参见教程。)
如果使用下面的代码将多个Foo
对象添加到列表中,则每个实例将从调用getValue()
返回3
:
这里,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);
}
List List=new ArrayList();
对于(int i=0;i<3;i++){
Foo tmp=new Foo();//您的问题在于类型static
,每次循环迭代时都需要新的初始化。如果您处于循环中,最好将具体的初始化保留在循环中
List<Object> objects = new ArrayList<>();
for (int i = 0; i < length_you_want; i++) {
SomeStaticClass myStaticObject = new SomeStaticClass();
myStaticObject.tag = i;
// Do stuff with myStaticObject
objects.add(myStaticClass);
}
List objects=new ArrayList();
for(int i=0;i
而不是:
List<Object> objects = new ArrayList<>();
SomeStaticClass myStaticObject = new SomeStaticClass();
for (int i = 0; i < length; i++) {
myStaticObject.tag = i;
// Do stuff with myStaticObject
objects.add(myStaticClass);
// This will duplicate the last item "length" times
}
List objects=new ArrayList();
SomeStaticClass myStaticObject=新的SomeStaticClass();
for(int i=0;i
这里,tag
是SomeStaticClass
中的一个变量,用于检查上述代码段的有效性;您可以根据您的用例使用其他一些实现。每次向ArrayList添加对象时,请确保您添加了一个新的对象而不是尚未使用的对象。当您添加相同的1个同一个对象被添加到ArrayList中的不同位置。当您对一个对象进行更改时,因为同一个副本被一次又一次地添加,所以所有副本都会受到影响。
例如
假设您有这样一个ArrayList:
ArrayList<Card> list = new ArrayList<Card>();
Card c = new Card();
public Card(Card c){
this.property1 = c.getProperty1();
this.property2 = c.getProperty2();
... //add all the properties that you have in this class Card this way
}
假设您有相同的1张卡副本,因此在添加新对象时,您可以执行以下操作:
list.add(new Card(nameOfTheCardObjectThatYouWantADifferentCopyOf));
日历实例也有同样的问题
错误代码:
Calendar myCalendar = Calendar.getInstance();
for (int days = 0; days < daysPerWeek; days++) {
myCalendar.add(Calendar.DAY_OF_YEAR, 1);
// In the next line lies the error
Calendar newCal = myCalendar;
calendarList.add(newCal);
}
它还可能导致使用相同的引用而不是使用新的引用
List<Foo> list = new ArrayList<Foo>();
setdata();
......
public void setdata(int i) {
Foo temp = new Foo();
tmp.setValue(i);
list.add(tmp);
}
List List=new ArrayList();
setdata();
......
公共无效设置数据(int i){
Foo temp=新的Foo();
tmp.设定值(i);
添加列表(tmp);
}
而不是:
List<Foo> list = new ArrayList<Foo>();
Foo temp = new Foo();
setdata();
......
public void setdata(int i) {
tmp.setValue(i);
list.add(tmp);
}
List List=new ArrayList();
Foo temp=新的Foo();
setdata();
......
公共无效设置数据(int i){
tmp.设定值(i);
添加列表(tmp);
}
hello@Duncan nice solution,我想问你,在“添加同一对象”中,为什么三个不同的实例会包含值2,不是所有三个实例都应该包含3个不同的值吗?希望你能尽快回复,thanks@Dev因为同一个对象(tmp
)被添加到列表中三次。由于调用tmp.setValue(2),该对象的值为2
在循环的最后一次迭代中。好吧,这里的问题是因为同一个对象,如果我在数组列表中添加同一个对象三次,arraylist obj的所有三个位置都将引用同一个对象,是吗?@Dev-Yup,确实如此。我最初忽略了一个明显的事实:关于部分,每次都必须创建一个新实例ou loop
在添加相同对象一节中:请注意,引用的实例涉及的是您正在添加的对象,而不是您正在添加的对象。您所说的“typestatic
”是什么意思?对您来说什么是非静态类?例如,非静态:公共类SomeClass{/*somecode*/}
&static:公共静态类SomeStaticClass{/*somecode*/}
。我希望现在更清楚。因为,一个静态类的所有对象共享相同的地址,如果它们在循环中初始化,并且在每次迭代中使用不同的值进行设置。所有这些对象最终都将具有相同的值,该值将等于上一次迭代的值或修改最后一个对象时的值。我希望现在更清楚。为了将来读者:你根本不应该使用日历。
Calendar myCalendar = Calendar.getInstance();
for (int days = 0; days < daysPerWeek; days++) {
myCalendar.add(Calendar.DAY_OF_YEAR, 1);
// RIGHT WAY
Calendar newCal = (Calendar) myCalendar.clone();
calendarList.add(newCal);
}
List<Foo> list = new ArrayList<Foo>();
setdata();
......
public void setdata(int i) {
Foo temp = new Foo();
tmp.setValue(i);
list.add(tmp);
}
List<Foo> list = new ArrayList<Foo>();
Foo temp = new Foo();
setdata();
......
public void setdata(int i) {
tmp.setValue(i);
list.add(tmp);
}