Is the copy constructor of Java's ArrayList shallow copy or deep copy?
Asked Answered
R

2

6

I have long being confused with whether Java's container's copy constructor is shallow copy or deep copy? Below is my understanding: ints1, ints2, ints3 are references so they lie in stack. inst1 points to some object in heap, and this object holds three anonymous references that lie in stack, and they point to Objects that have int value 0, 1, 2 seperately.

ints2 = ints1

so ints2 points to the same object as ints1. So change objects pointed by refenences in ints2 will influence those in ints2.

ints2.set(1,0+10)

will change refenence ints1.get(0)'s object.

ints3 = new ArrayList<>(ints1)

Next is my confusion.

If copy constructor is shallow copy, then although ints1 and ints3 point to different object, the two objects have same references! So any action to change objects by manipulating reference in ints1 will changes ints3, because they are pointing to the same objects.

If copy constructor is deep copy, then ints1 and ints3 will hold different references and point to different objects. Then the change in ints1 will not influence that in ints3.

According to the result, it seems that the copy constructor is deep copy, not shallow copy.

Hope someone can correct me, thanks.

import java.util.*;
public class MyClass {
    public static void main(String args[]) {
       List<Integer> ints1 = new ArrayList<>(Arrays.asList(0,1,2));
       System.out.println(ints1);
       List<Integer> ints2 = ints1;
       ints2.set(0,0+10);
       System.out.println(ints1);
       List<Integer> ints3 = new ArrayList<>(ints1);
       ints3.set(1,1+10);
       System.out.println(ints1);
    }
}
result
[0, 1, 2]
[10, 1, 2]
[10, 1, 2]
Rausch answered 18/12, 2017 at 5:39 Comment(2)
Don't confuse the immutability of Integer with shallow vs deep copies. Have a read of this: yunmingzhang.wordpress.com/2014/01/08/…Buckinghamshire
ints1 and ints2 are referencing same objects while ints3 is a separate object which was created using values in ints1. So any changes in ints2 will change ints1. but changes in ints3 will not affect other two objects.. if you have confusion try to print hashcode of all objects, you can see the difference then..Chemosmosis
A
0

The answer is : shallow copy. Have a look at this post which gives more details on the topic: http://javarevisited.blogspot.co.uk/2014/03/how-to-clone-collection-in-java-deep-copy-vs-shallow.html?m=1

Amethist answered 18/12, 2017 at 5:52 Comment(0)
P
0

The crux of the issue is that when you do ints3.set(1, 1+10) you are actually changing the reference that was stored in ints3[1]. The reference stored in ints1[1] remains unaffected from this.

// Format

 ---------- 
|  Value   |
 ---------- 
  Address


// Actual data
------       ------      -------            ------
|  1   | ...|   2  | ... |  3  |   ...... |  42   |  
------       ------      -------            ------
   10          20           30                80


// ArrayList <Integer> a = new ArrayList <Integer> (Arrays.asList(1, 2, 3));
------        ------ ------ ------
| 100 | ---> |  10  |  20  |  30  |
------        ------ ------ ------
  a             100    104    108


// ArrayList <Integer> b = new ArrayList <Integer> (a);
------        ------ ------ ------
| 200 | ---> |  10  |  20  |  30  |
------        ------ ------ ------
  b             200    204    208


When you do:

a[1] = 42, it is equivalent to:

------        ------ ------ ------
| 100 | ---> |  10  |  80  |  30  |
------        ------ ------ ------
  a             100    104    108


Note that this does not change b in any way.

Also, take a look at the following code. Here you can see that it is indeed Shallow Copy because when you modify the value pointed to by the reference, it is reflected in both a and b.

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;

class Node {

    int data;
    String name;

    Node(int data, String name) {

        this.data = data;
        this.name = name;
    }

    public String toString() {

        return "{" + Integer.toString(data) + ", " + name + "}";
    }
}

class ArrayListTest {

    public static void main(String[] args) {

        ArrayList <Node> a = new ArrayList <Node>();

        Node n[] = new Node[5];
        for(int i = 0; i < 5; i++) {
            n[i] = new Node(i, Integer.toString(i));
        }

        a.add(n[0]);
        a.add(n[1]);
        a.add(n[2]);

        System.out.println("Previously: ");
        System.out.println("a = " + a.toString());

        ArrayList <Node> b = new ArrayList <Node> (a);

        System.out.println("b = " + b.toString());

        // This does not affect b as b has aready made a copy of 
        // all the references in a different location.
        a.add(n[3]);

        n[2].data = 10;
        n[2].name = "10";

        System.out.println("\nCurrent: ");
        System.out.println("a = " + a.toString());
        System.out.println("b = " + b.toString());

    }
}
Paperboard answered 14/8, 2018 at 13:7 Comment(5)
So basically when you create a clone, using copy constructor it just creates a shallow copy, but when you modify the content of the object, it creates a deep copy in a different memory location? Is my understanding correct?Appetite
@Appetite Clone creates a shallow copy. Modifying the contents of the object will not create a new object in memory. Like in my code example above, I was able to modify the content of n[2] and it was reflected in both the ArrayLists because I didn't change the reference to the object that is stored in the ArrayLists. However, if I modify it like a.set(1, n[0]) only then the reference stored in the ArrayList a will change but b will remain unaffected.Paperboard
Well, that's what i was asking. If ArrayList is modified as you said, ie a.set(1, n[0]), then the reference stored in a will change, doesn't that mean an independent ArrayList w.r.t b is generated in a new memory location? ie a deep copy?Appetite
@Appetite a new list is not generated with respect to b.Paperboard
I still don't get it. if a new list is not generated, then how come when list a is modified ,list b remains unaffected? a 's hashcode changes as well but b 's hashcode remains same. Both a and b refers different memory locations and list's content is different as well. If a new list is not generated then how is this possible?Appetite

© 2022 - 2024 — McMap. All rights reserved.