Why does my ArrayList contain N copies of the last item added to the list?

I add three different objects to an ArrayList, but the list contains three copies of the last object I added.

For example:

for (Foo f : list) { System.out.println(f.getValue()); } 

Expected:

 0 1 2 

Actual:

 2 2 2 

What mistake did I make?

Note: this is for canonical Q&A for a lot of similar problems arising on this site.

+71
java arraylist list static
Nov 07 '13 at 18:11
source share
4 answers

This problem has two typical causes:

  • Static fields used by objects that you saved in the list

  • Accidentally adding the same object to the list

Static fields

If the objects in your list store data in static fields, each object in your list will look the same, since it contains the same values. Consider the class below:

 public class Foo { private static int value; // ^^^^^^------------ - Here the problem! public Foo(int value) { this.value = value; } public int getValue() { return value; } } 

In this example, there is only one int value that is used by all instances of Foo because it is declared as static . (See the “Understanding Class Members” textbook.)

If you add multiple Foo objects to the list using the code below, each instance will return 3 from the getValue() call:

 for (int i = 0; i < 4; i++) { list.add(new Foo(i)); } 

The solution is simple - do not use static keywords for fields in your class unless you really want the values ​​to be shared between each instance of this class.

Adding the same object

If you add a temporary variable to the list, you must create a new instance of the object you add each time you loop. Consider the following piece of error code:

 List<Foo> list = new ArrayList<Foo>(); Foo tmp = new Foo(); for (int i = 0; i < 3; i++) { tmp.setValue(i); list.add(tmp); } 

Here the tmp object was created outside the loop. As a result, the same instance of the object is added to the list three times. The instance will contain the value 2 , because it was the value passed during the last call to setValue() .

To fix this, simply move the object's construction into a loop:

 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); } 
+120
Nov 07 '13 at 18:11
source share

Your problem is with the static type, which requires a new initialization every time the loop repeats. If you are in a loop, it is best to keep the specific initialization inside the loop.

 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); } 

Instead:

 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 } 

Here tag is a variable in SomeStaticClass to check the accuracy of the above snippet; you may have some other implementation based on your use case.

+6
Jul 13 '16 at 12:31
source share

There were problems with the calendar copy.

Invalid code:

 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); } 

You must create a NEW calendar object that can be executed using calendar.clone() ;

 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); } 
+4
Oct 24 '17 at 20:45
source share

Each time you add an object to an ArrayList, be sure to add a new object and an object not yet used. It happens that when you add the same copy of an object, this object is added at different positions in the ArrayList. And when you make changes to one, because the same copy is added again and again, all copies become affected. For example, let's say you have an ArrayList:

 ArrayList<Card> list = new ArrayList<Card>(); Card c = new Card(); 

Now, if you add this map c to the list, it will be added without problems. It will be saved in location 0. But when you save the same Map c in the list, it will be saved in location 1. So remember that you added the same 1 object to two different locations in the list. Now, if you make changes to the Card c object, the objects in the list at locations 0 and 1 also reflect this change, because they are the same object.

One solution would be to make a constructor of the Card class that accepts another card object. Then in this constructor you can set such properties as follows:

 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 } 

And let's say you have the same 1 copy of the Map, so when adding a new object, you can do this:

 list.add(new Card(nameOfTheCardObjectThatYouWantADifferentCopyOf)); 
+3
Feb 27 '17 at 6:21
source share



All Articles