1

I have an array of ArrayLists. I'm iterating over them using a variable called 'al' and changing the contents of that arraylist. However, I see that the contents of the original array of ArrayList have changed. Why is this?

I was expecting that since I am only changing the contents of a new variable called 'al', the contents of the original array of ArrayLists, ie alal wouldn't change.

Are these operating on memory directly? What is this concept called, if I would like to read a bit more about it.

    package proj;

    import java.util.ArrayList;

    public class Ask
    {
        public static void main(String[] args)
        {
            ArrayList<Integer> myArrayList1 = new ArrayList<Integer>();
            myArrayList1.add(1);
            myArrayList1.add(1);
            myArrayList1.add(1);

            ArrayList<Integer> myArrayList2 = new ArrayList<Integer>();
            myArrayList2.add(2);
            myArrayList2.add(2);
            myArrayList2.add(2);

            ArrayList<ArrayList<Integer>> alal = new ArrayList<ArrayList<Integer>>();
            alal.add(myArrayList1);
            alal.add(myArrayList2);

            for(ArrayList<Integer> al : alal)
            {
                al.set(0, 99);
            }

            System.out.println(alal);
        }
    }

EDIT : I'm trying to edit my code based on SMA's post so that my contents still remain the same even upon using the set method. This is what I have tried, but my output still reflects the change [[99, 1, 1], [99, 2, 2]]

package proj;

import java.util.ArrayList;

public class Ask
{
    public static void main(String[] args)
    {
        ArrayList<Integer> myArrayList1 = new ArrayList<Integer>();
        myArrayList1.add(1);
        myArrayList1.add(1);
        myArrayList1.add(1);

        ArrayList<Integer> myArrayList2 = new ArrayList<Integer>();
        myArrayList2.add(2);
        myArrayList2.add(2);
        myArrayList2.add(2);

        ArrayList<ArrayList<Integer>> alal = new ArrayList<ArrayList<Integer>>();
        alal.add(new ArrayList<Integer>(myArrayList1));//creating seperate instance of array list with same content as original list
        alal.add(new ArrayList<Integer>(myArrayList2));
        for(ArrayList<Integer> al : alal)
        {
            al.set(0, 99);
        }
        System.out.println(alal);
    }
}

EDIT 2 : However, I don't see the same behavior in a normal ArrayList. Here the contents remain as [1, 2, 3] even after editing them to 99 inside the loop. So, are new instances of these variables created here? Aren't they mere references as before?

package proj;

import java.util.ArrayList;

public class Ask
{
    public static void main(String[] args)
    {
        ArrayList<Integer> myArrayList = new ArrayList<Integer>();
        myArrayList.add(1);
        myArrayList.add(2);
        myArrayList.add(3);

        for(int element : myArrayList)
        {
            element = 99;
        }

        System.out.println(myArrayList);

    }
}
tubby
  • 2,074
  • 3
  • 33
  • 55
  • possible duplicate of [How does the Java for each loop work?](http://stackoverflow.com/questions/85190/how-does-the-java-for-each-loop-work) – ka4eli Aug 09 '15 at 12:46

2 Answers2

2

I was expecting that since I am only changing the contents of a new variable called 'al'

alal contains references to ArrayLists. When you iterate over those ArrayLists, you are not creating new ArrayList objects. Therefore, any change in al is reflected in alal.

When you assign the reference of an existing object to a new reference variable (as you do in your for loop), you are not creating a new object. The new variable (al is your case) merely refers to the existing object.

If you wish to iterate over alal without changing the ArrayLists in contains, you must either create a copy of alal containing copies of the original ArrayLists, or use a different loop to iterate over alal while creating copies :

for (int i = 0; i < alal.length; i++) {
    ArrayLst<Integer> al = new ArrayList<Integer>(alal.get(i)); // create copy
    al.set(0, 99);
}

Of course, this loop doesn't make much sense, since you are modifying ArrayLists that will never be used anywhere. I'm assuming that in your real code you are doing something with the modified ArrayLists.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • thanks, I get it now. But how can I create new ArrayList objects and make sure that changes to al won't affect the original variables? Please see my edit above. – tubby Aug 09 '15 at 12:55
  • thanks, but please see Edit 2 above. Hmm, why is it that in a normal ArrayList, for the same scanario, new objects are created ? Why don't they refer to the existing object like before? – tubby Aug 09 '15 at 13:11
  • @PepperBoy In your second edit you are using assignment (`=`). Assignment can't change the value inside the ArrayList. To make your original code behave like edit 2, you'll have to change `al.set(0, 99);` to `al = new ArrayList(); al.add(99);` – Eran Aug 09 '15 at 13:19
  • thanks Eran for the help. I appreciate. So, just to confirm, it's the behavior of the set method to change the contents of the original variable. Assignment on the other hand almost treats it like a separate instance. Correct? – tubby Aug 09 '15 at 13:27
  • 1
    @PepperBoy Yes, the set method changes the contents of the original ArrayList. Assignment to a variable (such as `al = ..`) doesn't affect the contents of the previous object that was referred by that variable. – Eran Aug 10 '15 at 14:39
0

You are just using the same reference (reference within heap) of an array list with alal as the original one myArrayList1 and myArrayList2 and hence it acts on the same list and modifies the 0th index element.

If you don't want loop impacting original list, you should do something like:

ArrayList<ArrayList<Integer>> alal = new ArrayList<ArrayList<Integer>>();
alal.add(new ArrayList<Integer>(myArrayList1));//creating seperate instance of array list with same content as original list
alal.add(new ArrayList<Integer>(myArrayList2));
SMA
  • 36,381
  • 8
  • 49
  • 73