2

I am creating an ArrayList of ArrayList and adding ArrayLists to it. But everytime I make changes to the ArrayList, it is being reflected in the ArrayList<ArrayList>.

Example:

List<List<String>> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<String>();
list2.add("Cat");
list1.add(list2);  //no problem
list2.clear();
list2.add("Dog");
list1.add(list2);  //problem! the cat is replaced by two dogs this time!!

How do I make sure that updates to list2 is not reflected in list1?

DimaSan
  • 12,264
  • 11
  • 65
  • 75
ilakk
  • 69
  • 1
  • 8
  • Downvoted because for me it's unclear your first sentence "But everytime I make changes to the ArrayList, it is being reflected in the ArrayList". Deepen better this sentence. – nbro Sep 17 '16 at 23:55
  • 1
    Moreover, if you're using a IDE (Eclipse or Intellij), it should give you an error at this statement `List> list1 = new ArrayList>();`... – nbro Sep 17 '16 at 23:56
  • Thanks Stephen and nbro, @nbro, No it is not giving me an error for List> list1 = new ArrayList>();... Why do you think so? I'm in fact creating an ArrayList of an object, not Strings. I gave it for an example – ilakk Sep 18 '16 at 00:28

2 Answers2

1

What I've observed from the following equivalent but runnable program:

import java.util.List;
import java.util.ArrayList;

public class Test1 {


    public static void main(String[] args){

        List<ArrayList<String>> list1 = new ArrayList<ArrayList<String>>();    
        ArrayList<String> list2 = new ArrayList<String>();

        list2.add("Cat");
        System.out.println(list2);

        list1.add(list2); 
        System.out.println(list1);

        list2.clear();
        System.out.println(list2);

        list2.add("Dog");
        System.out.println(list2);

        list1.add(list2);
        System.out.println(list2);
        System.out.println(list1);

        if(list1.get(0) == list1.get(1)) {
            System.out.println("Lists at position 0 and 1 are the same");
        }

    }
}

it's not that "the cat is replaced by two dogs" as you wrote in a comment of your code but that, at the end, i.e. after the last statement, list1 contains two lists, each of them containing a "Dog".

This is of course due to the fact that when you add list2 to list1 the second time, you're not adding actually a new list, but the same one. You probably thought that by clearing the list2 and then adding it again would add a new list with a new item "Dog", but what you actually did was modifying the same object and adding the same reference. Remember that list2 and list1 are references!

What you need to do is create a new ArrayList object, like:

ArrayList<String> list3 = new ArrayList<String>();
list3.add("Dog");
list1.add(list3);

instead of clearing list2 and adding it again.

Check also these articles:

  1. Why can't you have a "List<List<String>>" in Java?

  2. Working with a List of Lists in Java

  3. What are classes, references and objects?

Community
  • 1
  • 1
nbro
  • 15,395
  • 32
  • 113
  • 196
1

Short answer ... replace

list2.clear();

with

list2 = new ArrayList<String>();

The problem is happening because list1.add(list2) adds a reference to list2 to list1. It is NOT making a copy of the list that list2 refers to, at any point. So you end up adding multiple references to the same list object to list1.

This is a consequence of the way that Java argument passing works, and the way that the collection APIs have all been designed to work.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216