Skip to content
Advertisement

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

I’m adding 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 have I made?

Note: this is designed to be a canonical Q&A for the numerous similar issues that arise on this site.

Advertisement

Answer

This problem has two typical causes:

  • Static fields used by the objects you stored 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 appear to be the same because they hold the same values. Consider the class below:

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

In that example, there is only one int value which is shared between all instances of Foo because it is declared static. (See “Understanding Class Members” tutorial.)

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

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

The solution is simple – don’t use the static keywords for fields in your class unless you actually want the values shared between every instance of that class.

Adding the Same Object

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

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 constructed outside the loop. As a result, the same object instance is being added to the list three times. The instance will hold the value 2, because that was the value passed during the last call to setValue().

To fix this, just move the object construction inside the 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);
}
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement