Java - Implement deep and shallow copy of an array

可紊 提交于 2019-12-06 23:01:13

问题


I am trying to understand the concept of shallow vs deep copy in Java. There is a lot of articles and Q&A about this subject, but whenever I try to implement these concepts in a real Java code, everything become unclear to me.

One of the answers on which I base my understanding is in this link, where deep and shallow copying are explained via schemas.

I will show you below my implementation for each case:

  • Shallow copy:

I took for my example the method System.arraycopy() as I read in many articles that it performs a shallow copy (along with the clone method)

public class Test {

    public static void main(String[] args) {
        NameValue[] instance1 = {
                new NameValue("name1", 1),
                new NameValue("name2", 2),
                new NameValue("name3", 3),
        };
        NameValue[] instance2 = new NameValue[instance1.length];

        // Print initial state
        System.out.println("Arrays before shallow copy:");
        System.out.println("Instance 1: " + Arrays.toString(instance1));
        System.out.println("Instance 2: " + Arrays.toString(instance2));

        // Perform shallow copy
        System.arraycopy(instance1, 0, instance2, 0, 3);

        // Change instance 1
        for (int i = 0; i < 3; i++) {
            instance1[i].change();
        }

        // Print final state
        System.out.println("Arrays after shallow copy:");
        System.out.println("Instance 1: " + Arrays.toString(instance1));
        System.out.println("Instance 2: " + Arrays.toString(instance2));
    }

    private static class NameValue {
        private String name;
        private int value;

        public NameValue(String name, int value) {
            super();
            this.name = name;
            this.value = value;
        }

        public void change() {
            this.name = this.name + "-bis";
            this.value = this.value + 1;
        }

        @Override
        public String toString() {
            return this.name + ": " + this.value;
        }
    }
}

The result of the execution of the main methods is as follows:

Arrays before shallow copy:
Instance 1: [name1: 1, name2: 2, name3: 3]
Instance 2: [null, null, null]
Arrays after shallow copy:
Instance 1: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
Instance 2: [name1-bis: 2, name2-bis: 3, name3-bis: 4]

this result is an accordance with the schema of the previous link:

  • Deep copy:

I took for this example the method Arrays.copyOf() as I read in many articles that it performs a deep copy (along with the Arrays.copyOfRange method)

public static void main(String[] args) {
    NameValue[] instance1 = {
            new NameValue("name1", 1),
            new NameValue("name2", 2),
            new NameValue("name3", 3),
    };
    NameValue[] instance2 = new NameValue[instance1.length];

    // Print initial state
    System.out.println("Arrays before deep copy:");
    System.out.println("Instance 1: " + Arrays.toString(instance1));
    System.out.println("Instance 2: " + Arrays.toString(instance2));

    // Perform deep copy
    instance2 = Arrays.copyOf(instance1, 3);

    // Change instance 1
    for (int i = 0; i < 3; i++) {
        instance2[i].change();
    }

    // Print final state
    System.out.println("Arrays after deep copy:");
    System.out.println("Instance 1: " + Arrays.toString(instance1));
    System.out.println("Instance 2: " + Arrays.toString(instance2));
}

which displays:

Arrays before deep copy:
Instance 1: [name1: 1, name2: 2, name3: 3]
Instance 2: [null, null, null]
Arrays after deep copy:
Instance 1: [name1-bis: 2, name2-bis: 3, name3-bis: 4]
Instance 2: [name1-bis: 2, name2-bis: 3, name3-bis: 4]

If we base the deep copy logic on the previous schema, this should be the result:

As you may notice, the result of the execution of the main method is different from the logic of the schema above.

Any explanation will be welcome.


回答1:


I am trying to understand the concept of shallow vs deep copy in Java.

In Java you pass around and store references to objects not the objects themselves.
So when you have an NameValue[] array the array does not contain the objects NameValue but references to the objects.
So when you do a shallow copy to NameValue[] array2 it means you are just copying the references from one array to the other. Which effectively means that now both array and array2 refer to exactly the same objects and any change you do from array[2] will be visible from array2[2] (same object).

When you deep copies you copy each object completely to another memory area and you keep a reference to that new object in your new array.
This way the 2 arrays now refer to different objects and any change to array[2] are not visible from array2[2]

Update:
This does not apply to primitives that do store the actual value and not a reference.
So an int[] a when you copy you get a copy of the values (i.e. deep copy in a sense) because a[2] contains the value itself and not the reference to the value.




回答2:


I don't know where you read that copyOf() performs a deep copy, because that is just plain wrong.

Quoting javadoc of Arrays.copyOf(T[] original, int newLength):

For all indices that are valid in both the original array and the copy, the two arrays will contain identical values.

That means it's a shallow copy. To be a deep copy, the values would have to point to different objects, since the referenced object would have to be a copy too.

To perform a deep copy, you have to iterate the array and copy the values. Java can't do that for you, because it doesn't know how to copy the object.

E.g. how would Java know how to copy a NameValue object? clone()? Copy constructor? Serialize+Deserialize? Factory method? Other means?




回答3:


I think there is a little missunderstanding that Arrays.copyOf() produces a deep copy.

Arrays.copyOf() makes a new array that contains old refrences to objects that are not being copied and as the link that I've added explains in the case of nested arrays they will not get copied and hence it can't be considered a deep copy but a shallow copy.

See this for more information.



来源:https://stackoverflow.com/questions/38641495/java-implement-deep-and-shallow-copy-of-an-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!