clone() and system.arracopy() of an array creates two arrays with different references in Java?

StackOverflow https://stackoverflow.com/questions/18772913

سؤال

Firstly I have to say this is not a duplicate of deep copying vs shallow copying (clone) in Java. but it is related to that. I have read other posts on deep vs shallow copying in SO and while working on this, I found some problem with my understanding. Question is : clone() and system.arraycopy() gives different arrays in the below example. but they aren't supposed to?

I used array as a field in another example object below. There again I see they are different references for the arrays fields. The code is commented for easy following.

import java.util.Arrays;
import java.util.*;


class Example {
        public int foo;
        public int[] bar;

        public Example (int foo, int[] bar) {
         this.foo = foo; 
        this.bar = bar; 
        }
        public void setfoo(int foo){
            this.foo=foo;
        }
        public int[] getbar(){
            return bar;
        }
}
public class ClonevsDeepCopy {
    public static void main(String[] args){
        //Example 1
        StringBuffer[] arr = {new StringBuffer("abc"),new StringBuffer("def"),
                                     new StringBuffer("ghi")};
        StringBuffer[] arr2 = arr.clone();
        StringBuffer[] arr3 = new StringBuffer[3];
        System.arraycopy(arr, 0, arr3, 0, 2);
        //check for identity
        System.out.println(arr==arr2);
        System.out.println(arr==arr3);
        //End of example 1

        //Example 2
        /*this is equivalent of shallow copying which is clone()
         * The normal interpretation is that a "shallow" copy of eg1 
         * would be a new Example object whose foo equals 1 
         * and whose bar field refers to the same array as in the original; e.g.
         */
        Example eg1 = new Example(1, new int[]{1, 2});
        Example eg2 = new Example(eg1.foo,eg1.bar);
        System.out.println(eg1.bar==eg2.bar);
        eg1.setfoo(4);
        eg1.bar[0]=99;

        /*This is equivalent of deep coying
        The normal interpretation of a "deep" copy of eg1 would 
        be a new Example object whose foo equals 
        1 and whose bar field refers to a copy of the original array; e.g.
        */
        Example eg3 = new Example(eg1.foo,Arrays.copyOfRange(eg1.bar, 0, 2));
        System.out.println(eg3.bar==eg1.bar);
        //cloning on array
        Example eg4 = new Example(eg1.foo,eg1.bar.clone());
        System.out.println(eg4.bar==eg1.bar);
        //End of example 2




    }

}
هل كانت مفيدة؟

المحلول

There's nothing strange here.

If arr1 is the result or arr.clone() then arr1!=arr but arr1[0]==arr[0] if it is defined. If arr1=arr is the assignment then arr1==arr.

Details:

We have 5 results:

false at System.out.println(arr==arr2);:

Nothing strange here, we're comparing the array references themselves, not the contents.

false at System.out.println(arr==arr3);

Nothing strange, different arrays.

true at System.out.println(eg1.bar==eg2.bar);:

Nothing strange, same references.

Last two false:

Again, we're performing some shallow copies. The elements are still equal references, but the arrays are different references.

نصائح أخرى

I don't know what is confusing you. System.arraycopy() copies elements from one array to another. It doesn't play with reference.

Array#clone() javadoc states

The general intent is that, for any object x, the expression:

x.clone() != x

Therefore you will get different references.

More detail

StringBuffer[] arr = {new StringBuffer("abc"),new StringBuffer("def"),
                                 new StringBuffer("ghi")};
StringBuffer[] arr2 = arr.clone();
StringBuffer[] arr3 = new StringBuffer[3];

You have 3 different references. Then, see code comments

System.arraycopy(arr, 0, arr3, 0, 2); // copy values from arr into arr, the references haven't changed
//check for identity
System.out.println(arr==arr2); // different references
System.out.println(arr==arr3); // different references

Arrays.copyOf() returns a new array (new reference) with values from the source array.

Example eg3 = new Example(eg1.foo,Arrays.copyOfRange(eg1.bar, 0, 2));

Therefore

System.out.println(eg3.bar==eg1.bar);

is false.

And more

   Example eg4 = new Example(eg1.foo,eg1.bar.clone());
   System.out.println(eg4.bar==eg1.bar);

clone() returns a new reference, so you are again comparing different references and get false.

If you're looking to compare the contents of the arrays, use

Arrays.equals(arr, arr2); // for example

Note that here it doesn't matter because of primitive types, but if your array held reference types, you might care about shallow or deep copies.

Much confusion will be avoided if you regard type object and all its derivatives as holding "object identifiers". A variable of type StringBuffer doesn't hold an instance of StringBuffer--it holds an object identifier which, if non-blank (i.e. not null), will identify an instance of StringBuffer. Likewise, a variable of type StringBuffer[] doesn't hold an array--it holds an object identifier which, if non-blank, will identify an instance of StringBuffer[] which, in turn, won't hold instances of StringBuffer, but will instead identify them.

When code says someVariable.someMember=5;, the code isn't writing to someVariable. Instead, it examines someVariable, notices which object it identifies, and then modifies the appropriate field of that object. It may look as though the right-hand part of the statement has something to do with someVariable, but it doesn't. Once the system determines what object is identified by someVariable, that variable will be out of the picture.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top