Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

System.arraycopy() shallow copy or deepcopy with primitive and object references

I read somewhere that System.arraycopy does create a new copy for primitive data types and shallow copy for object references.

so, that I started the experiment that with below code

//trying with primitive values
int a[] ={1,2,3};
int b[] = new int[a.length];
System.arraycopy(a,0,b,0,a.length);
b[0] = 9;
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
//now trying with object references
Object[] obj1 = {new Integer(3),new StringBuffer("hello")};
Object[] obj2 = new Object[obj1.length];
System.arraycopy(obj1,0,obj2,0,obj1.length);
obj1[1] = new StringBuffer("world");
System.out.println(Arrays.toString(obj1));
System.out.println(Arrays.toString(obj2));

and the output was

[1, 2, 3]
[9, 2, 3]
[3, world]
[3, hello]

But what I expected was

[1, 2, 3]
[9, 2, 3]
[3, world]
[3, world]

from the above code, I understood that System.arraycopy does deep copy for object references If so, how obj1[0] == obj2[0] gives true

like image 388
gajapathy p Avatar asked Mar 10 '23 10:03

gajapathy p


2 Answers

You have a misconception.

Once you do

obj1[1] = new StringBuffer("world");

You have replaced the reference in obj1[1]. Now the two arrays contain different references to different objects.

If you want to see that what was copied was the actual reference, you should try instead:

obj1[1].setLength(3);

Now both obj1[1] and obj2[1] should contain the string hel, because you did not replace the reference but rather changed the content.

like image 54
RealSkeptic Avatar answered Mar 12 '23 00:03

RealSkeptic


System.arraycopy does shallow copy, which means it copies Object references when applied to non primitive arrays.

Therefore after System.arraycopy(obj1,0,obj2,0,obj1.length);, obj1[0]==obj2[0] and obj1[1]==obj2[1], since both arrays hold references to the same Objects.

Once you assign a new value to obj1[1], obj1[1] no longer refers to the same StringBuffer instance as obj2[1]. That's why the outputs of Arrays.toString(obj1) and Arrays.toString(obj2) are different.

If instead of

obj1[1] = new StringBuffer("world");

you would write

obj1[1].setLength(0);
obj1[1].append("world");

both print statements would output [3, world], since both arrays would still refer to the same StringBuffer instance.

like image 26
Eran Avatar answered Mar 11 '23 22:03

Eran