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

时间:2017-12-18 05:39:54

标签: java constructor copy-constructor deep-copy

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]

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

问题的症结在于,当您执行ints3.set(1, 1+10)时,实际上是在更改存储在ints3[1]中的引用。存储在ints1[1]中的引用不受此影响。

// 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.

另外,请看下面的代码。在这里您可以看到它确实是“浅拷贝”,因为当您修改引用所指向的值时,它会同时反映在ab中。

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

    }
}