Win a copy of Kotlin in Action this week in the Kotlin forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

does creating shallow copy means sharing same object by reference variables?  RSS feed

 
Ganish Patil
Ranch Hand
Posts: 529
19
Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Netbeans IDE Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Here is my code where I created shallow copy of an object using clone method. I just want to know does cloning creates new another object or just both reference variables here newKeywordObj1 and shallowCopyObj share the same object? because changing value of 0th index of arrayValue array also changing value of shallowCopyObj object when printed. if those two reference variables newKeywordObj1 and shallowCopyObj share the same object then why both objects have different hash code? If I'm not wrong each object have a unique hash code.

Output:************Object created by new keyword************
Object hashCode: 1284693 Value:10 Name: Java
1
2
3
4
5
************Object created by clone method************
Object hashCode: 31168322 Value:10 Name: Java
1
2
3
4
5
************After changing values of field of Object created by new keyword************
Output by newkeyword object
Object hashCode: 1284693 Value:10 Name: Java
100
2
3
4
5
Output by cloned object
Object hashCode: 31168322 Value:10 Name: Java
100
2
3
4
5
 
Ganish Patil
Ranch Hand
Posts: 529
19
Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Netbeans IDE Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Please see image to know what I want to know
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ganish Patil wrote:I just want to know does cloning creates new another object or just both reference variables here newKeywordObj1 and shallowCopyObj share the same object?

Your question is a little confusing, but I'll try to answer. But first you need to understand the distinction between an object and a reference.

1. Ignoring cached values, the ONLY way to create an object in Java is with the new keyword. Now it's possible that a class may only provide "factory" methods, so as a client, you may never use one yourself; but the factory method itself will contain a 'new' call somewhere.

2. Once an object is created, it's reference can be assigned to any number of variables. So in the following case:
  String s1 = new String("Hello World");
  String s2 = s1;

both s1 and s2 will contain a reference to the same String object.

3. All arrays In Java are objects, so similarly:
  int[] a1 = new int[] (1, 2, 3};
  int[] a2 = a1;

both a1 and a2 will contain a reference to the same array.

4. All arrays In Java are mutable. That means that you can change the contents of an element any time you want to. So, given the code in #3 above:
  a1[0] = 100;
  System.out.println(a2[0]);

will result in
  100
because a1[0] and a2[0] both refer to element 0 in the same array

So, getting back to the difference between "shallow" and "deep" copying: a "shallow" copy usually means that only references have been copied; NOT the objects themselves.

However, when it comes to cloning - and specifically cloning that uses the Cloneable interface (which is based on Object.clone()) correctly, the result is usually a "deep" copy - that is to say, every member object in the object being cloned will itself be copied, resulting in two objects with the same contents.

Unfortunately, arrays are an exception to that rule, and when Java clones an array, it creates a new array with each element copied - and if that element contains a reference, it simply copies the reference, NOT the object that it refers to.
Now generally, this is all you need, and in the above case - where each element is an int - it's exactly what you want, so:
  int[] a1 = new int[] (1, 2, 3};
  int[] a2 = a1.clone();
  a1[0] = 100;
  System.out.println(a2[0]);

will result in
  1

But if an element is an object - and specifically, a mutable object - then you can still get "odd" results. For example:will result in
  100
because even though a1 and a2 are now different arrays, their 0 elements contain the same reference, so when you use it, you're updating the same object.

Hope I haven't muddied the waters too much for you, but that's a 'potted' version of the difference between "shallow" and "deep" copying, and hopefully explains why you're seeing what you're seeing.

Winston
 
Ganish Patil
Ranch Hand
Posts: 529
19
Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Netbeans IDE Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Really splendid explanation,
Winston Gutkowski wrote: the ONLY way to create an object in Java is with the new keyword.
First time came to know, thought Class.forName() and clone methods etc. create an object but now got to know about factory methods. Yes I got the concept of shallow copy and deep copy.

As you gave example above I wrote a program.Output:
Original
1
2
3
Cloned
1
11
3
Here in above program got the correct output
But beneath in my new program
Wrong answer I got: When I change the value of 0th element of int[] marks of object myClsDeepCopyObj1 to 35 it is also changing the value of 0th element of int[] marks of object myClsNewKeywordObj1 which actually should be 80.
Correct answer I got of: When I changed the value of age variable of object myClsDeepCopyObj1 to 25 then only it's value is changed not myClsNewKeywordObj1. I also got about AtomicInteger idNumber as it is object reference so both points to same reference when changed both prints same value 201.



 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ganish Patil wrote:But beneath in my new program
Wrong answer I got: When I change the value of 0th element of int[] marks of object myClsDeepCopyObj1 to 35 it is also changing the value of 0th element of int[] marks of object myClsNewKeywordObj1 which actually should be 80.
Correct answer I got of: When I changed the value of age variable of object myClsDeepCopyObj1 to 25 then only it's value is changed not myClsNewKeywordObj1. I also got about AtomicInteger idNumber as it is object reference so both points to same reference when changed both prints same value 201.

And I suspect that's down to what I said above: When Java clones arrays, it creates a "shallow" copy, which is fine for primitives, and things like String[], but NOT for arrays of mutable objects.

If you want a truly deep copy, then you need to amend your clone() method, viz:Do you see the difference? Now you're forcefully copying each element of your idNumber array to a new object with the same value.

Note: I should probably have added that Object.clone() can handle any member that is itself Cloneable (including arrays) but, if you want a truly "deep" clone, you have to add code like the above to explicitly copy any member object that is (a) mutable, and (b) doesn't implement the Cloneable interface.

Not easy is it?

Winston
 
Ganish Patil
Ranch Hand
Posts: 529
19
Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Netbeans IDE Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote: When Java clones arrays, it creates a "shallow" copy, which is fine for primitives, and things like String[]

but this code is doing deep copy I think am I correct ?
Output:
Original
1
2
3
Cloned
1
11
3
because when I changed value of element at 1th location of int numbercopy[] doesn't change value at index 1 of int number[]. so they have different references means this clone copied complete object not reference, hope I'm on right path If this is doing deep copy then why this not doing deep copy of array of int in my main program on line no 96, below is code It does deep copy with int age variable on line no 90, here is code yes it's not that easy as I thought
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ganish Patil wrote:
Winston Gutkowski wrote: When Java clones arrays, it creates a "shallow" copy, which is fine for primitives, and things like String[]

but this code is doing deep copy I think am I correct ?

No, The reason it "works" is that ints are primitives, so when they are copied, you get a whole new value that is a copy of the original. And you'll get that whether your clone is "shallow" or "deep".

Strings are NOT primitives, they are objects, so they have a reference. However, they are also immutable - ie, you can't change them.

What you can do though is "simulate" a change by replacing a reference with a completely new String , viz:
  name = name.toUpperCase();
which replaces the reference in 'name' with one for a new String object containing only uppercase letters.

So if you clone an array of Strings, it will copy the references (a "shallow" copy); but this is normally sufficient because, since you cant "change" a String without replacing its reference, the elements in the two arrays will now point to two different String objects if you change one of them.

It's only when an object is mutable that you get problems - which is why you should generally avoid them if you can.
An AtomicInteger can be changed without affecting its reference, so if you want to truly "clone" an AtomicInteger[] array, you can't rely on Java to do it properly.

HIH

Winston
 
Ganish Patil
Ranch Hand
Posts: 529
19
Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Netbeans IDE Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Last doubt.
No, The reason it "works" is that ints are primitives, so when they are copied, you get a whole new value that is a copy of the original. And you'll get that whether your clone is "shallow" or "deep".
then array of int elements i.e. primitives in my main program is not showing different outputs as below code shows
Output:
Original
1
2
3
Cloned
1
11
3
I wrote another program so will be easy to understand what I'm not getting, here below is program like same above code just wrote in separate class. but when changed value of 1th index of array the output of both object's myNumbers[1] is same i.e. 300. Why this one is not different like myNumbers[1] of newKeywordclnObj1 should be 2 and only myNumbers[1] of deepCpyObj1 should be 300 as we got in above code? Output:
Output by newKeywordclnObj1 object
1
2
3
Output by deepCpyObj1 object
1
2
3
Output After changing values
Output by newKeywordclnObj1 object
1
300 // This actually should 2
3
Output by deepCpyObj1 object
1
300 // This is correct
3
 
Winston Gutkowski
Bartender
Posts: 10573
65
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ganish Patil wrote:Last doubt....I wrote another program so will be easy to understand what I'm not getting,..Why this one is not different like myNumbers[1] of newKeywordclnObj1 should be 2 and only myNumbers[1] of deepCpyObj1 should be 300 as we got in above code?[/b]

Because it looks like Object.clone() doesn't clone member objects - even if they're Cloneable - it simply copies their references (see the link above for the full docs).
Sorry if I misled you there, but it's ages since I actually wrote a clone() method.

Therefore your two arrays are NOT clones and you'll have to do it yourself; and the simplest way to do that for a primitive or immutable object array is:but for an array of mutable objects, you have to explicitly copy each element object and assign its reference to your new array, viz - if myNumbers is an AtomicInteger[]:Hope it makes sense.

Note: this is one case where you can't use a "getter". You must assign the value directly to the member field.

HIH. And sorry for steering you wrong before.

Winston
 
Ganish Patil
Ranch Hand
Posts: 529
19
Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Netbeans IDE Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Pardon me for late reply as I'm so lazy no consistency in study, it is this forum makes me study
Winston Gutkowski wrote:Note: this is one case where you can't use a "getter". You must assign the value directly to the member field.
yes got that now, both works very well as I expected. Thank you so much. Now I'm clear with these two concepts.
 
Consider Paul's rocket mass heater.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!