Shadow clone, Deep clone

Source: Internet
Author: User
Tags stringbuffer
What is Shadow clone.

The following example contains three class Unclonea,cloneb,clonemain. The Cloneb class contains a Unclonea instance and an int type variable, and overloads the Clone () method. The Clonemain class Initializes an instance of the Unclonea class B1, and then calls the Clone () method to generate a B1 copy b2. Finally, examine the output of B1 and B2:

Package clone;
Class Unclonea {
private int i;
Public Unclonea (int ii) {i = II}
public void Doublevalue () {i *= 2;}
Public String toString () {
return integer.tostring (i);
}
}
Class Cloneb implements cloneable{
public int aint;
Public Unclonea Unca = new Unclonea (111);
Public Object Clone () {
Cloneb o = null;
try{
o = (cloneb) super.clone ();
}catch (Clonenotsupportedexception e) {
E.printstacktrace ();
}
return o;
}
}
public class Clonemain {
public static void Main (string[] a) {
Cloneb B1 = new Cloneb ();
B1.aint = 11;
System.out.println ("Before clone,b1.aint =" + B1.aint);
System.out.println ("Before Clone,b1.unca =" + B1.unca);
Cloneb b2 = (cloneb) b1.clone ();
B2.aint = 22;
B2.unCA.doubleValue ();
System.out.println ("=================================");
System.out.println ("After clone,b1.aint =" + B1.aint);
System.out.println ("After Clone,b1.unca =" + B1.unca);
System.out.println ("=================================");
System.out.println ("After clone,b2.aint =" + B2.aint);
System.out.println ("After Clone,b2.unca =" + B2.unca);
}
}
/** RUN Result:
Before clone,b1.aint = 11
Before Clone,b1.unca = 111
=================================
After Clone,b1.aint = 11
After Clone,b1.unca = 222
=================================
After Clone,b2.aint = 22
After Clone,b2.unca = 222
*/

The results of the output show that the variant aint of type int and Unclonea instance object Unca have inconsistent clone results, the int type is truly clone, because changing the aint variable in B2 has no effect on B1 aint, that is to say, B2.aint and B1.aint already occupy a different memory space, B2.aint is a true copy of B1.aint. Conversely, changes to B2.unca change the B1.unca, and it is clear that B2.unca and B1.unca are just different references to the same object. As you can see, the result of invoking the Clone () method in the object class is to first create a space in memory that is the same as the original object, and then copy the contents of the original object as it is. For basic data types, such operations are not problematic, but for non-basic type variables, we know that they hold only references to objects, which also cause the primitive type variables after the clone to point to the same object as the corresponding variable in the original object.

Most of the time, the result of this clone is often not what we want, and this clone is also called "Shadow Clone". To make B2.unca point to objects different from B2.unca, and B2.unca to include the information in B1.unca as an initial message, you need to implement a deep clone.

How to do depth clone.

To change the above example to deep clone is simple and requires two changes: first, let the Unclonea class also implement the same clone function as the Cloneb class (Implementing the Cloneable interface, overloading the Clone () method). The second is to add a sentence O.unca = (unclonea) unca.clone () in the Cloneb Clone () method;

The procedure is as follows:

Package clone.ext;
Class Unclonea implements cloneable{
private int i;
Public Unclonea (int ii) {i = II}
public void Doublevalue () {i *= 2;}
Public String toString () {
return integer.tostring (i);
}
Public Object Clone () {
Unclonea o = null;
try{
o = (unclonea) super.clone ();
}catch (Clonenotsupportedexception e) {
E.printstacktrace ();
}
return o;
}
}
Class Cloneb implements cloneable{
public int aint;
Public Unclonea Unca = new Unclonea (111);
Public Object Clone () {
Cloneb o = null;
try{
o = (cloneb) super.clone ();
}catch (Clonenotsupportedexception e) {
E.printstacktrace ();
}
O.unca = (unclonea) unca.clone ();
return o;
}
}
public class Clonemain {
public static void Main (string[] a) {
Cloneb B1 = new Cloneb ();
B1.aint = 11;
System.out.println ("Before clone,b1.aint =" + B1.aint);
System.out.println ("Before Clone,b1.unca =" + B1.unca);
Cloneb b2 = (cloneb) b1.clone ();
B2.aint = 22;
B2.unCA.doubleValue ();
System.out.println ("=================================");
System.out.println ("After clone,b1.aint =" + B1.aint);
System.out.println ("After Clone,b1.unca =" + B1.unca);
System.out.println ("=================================");
System.out.println ("After clone,b2.aint =" + B2.aint);
System.out.println ("After Clone,b2.unca =" + B2.unca);
}
}
/** RUN Result:
Before clone,b1.aint = 11
Before Clone,b1.unca = 111
=================================
After Clone,b1.aint = 11
After Clone,b1.unca = 111
=================================
After Clone,b2.aint = 22
After Clone,b2.unca = 222
*/

It can be seen that the change in B2.unca now has no effect on B1.unca. At this point B1.unca and B2.unca pointed to two different unclonea instances, and at the Cloneb b2 = (cloneb) b1.clone (), the moment of invocation B1 and B2 had the same value, where b1.i = b2.i = 11.

Be aware that not all classes can achieve deep clone. For example, if you change the Unclonea type variable in the Cloneb class above to a stringbuffer type, look at the description of the StringBuffer in the JDK API, StringBuffer does not overload the Clone () method. More serious is stringbuffer or a final class, which is also said that we can not use the inheritance method to realize the StringBuffer clone indirectly. If a class contains objects with StringBuffer type objects or stringbuffer similar classes, we have two choices: either only shadow clones are implemented, or one sentence is added to the class's Clone () method (assuming the Sringbuffer object, And the variable name is still unca): O.unca = new StringBuffer (unca.tostring ()); The original is: O.unca = (unclonea) unca.clone ();

Also know that in addition to the basic data type can automatically achieve depth clone, the string object is an exception, it appears after the clone is also the implementation of the deep clone, although this is an illusion, but greatly facilitate our programming.

L The difference between string and StringBuffer in clones

It should be explained that the difference between string and StringBuffer is not highlighted here, but it is also possible to see some of the different parts of the string class in this example.

The following example includes two classes, the Clonec class contains a string type variable and a stringbuffer type variable, and the Clone () method is implemented. The CLONEC type variable C1 is declared in the Strclone class, and then the C1 clone () method is invoked to generate a copy c1 of C2, which prints the results after the string and C2 type variables in the StringBuffer are modified with the appropriate method:

Package clone;
Class Clonec implements cloneable{
Public String str;
Public StringBuffer Strbuff;
Public Object Clone () {
Clonec o = null;
try{
o = (Clonec) super.clone ();
}catch (Clonenotsupportedexception e) {
E.printstacktrace ();
}
return o;
}
}
public class Strclone {
public static void Main (string[] a) {
Clonec C1 = new Clonec ();
C1.str = new String ("Initializestr");
C1.strbuff = new StringBuffer ("Initializestrbuff");
System.out.println ("Before clone,c1.str =" + c1.str);
System.out.println ("Before clone,c1.strbuff =" + C1.strbuff);
Clonec C2 = (Clonec) c1.clone ();
C2.str = c2.str.substring (0,5);
C2.strbuff = C2.strBuff.append ("Change Strbuff clone");
System.out.println ("=================================");
System.out.println ("After clone,c1.str =" + c1.str);
System.out.println ("After clone,c1.strbuff =" + C1.strbuff);
System.out.println ("=================================");
System.out.println ("After clone,c2.str =" + c2.str);
System.out.println ("After clone,c2.strbuff =" + C2.strbuff);
}
}
/* RUN Result
Before clone,c1.str = Initializestr
Before clone,c1.strbuff = Initializestrbuff
=================================
After clone,c1.str = Initializestr
After Clone,c1.strbuff = Initializestrbuff change Strbuff clone
=================================
After clone,c2.str = Initi
After Clone,c2.strbuff = Initializestrbuff change Strbuff clone
*
*/

As you can see from the printed results, the string variable seems to have implemented a deep clone because the changes to C2.STR do not affect c1.str. Does Java think of sring classes as basic data types? In fact, there is a small trick, the secret lies in C2.str = C2.str.substring (0,5) this statement. Essentially, C1.STR and c2.str are still references at clone, and all point to the same string object. However, when executing c2.str = c2.str.substring (0,5), it acts as a new string type and then assigns it back to C2.STR. This is because string was written by Sun's engineers as an immutable class (immutable Class), and functions in all string classes cannot change their own values. Here's a very simple example:

Package clone;

public class Strtest {public static void main (string[] args) {

String str1 = "This is a test for immutable";

String str2 = str1.substring (0,8);

System.out.println ("Print str1:" + str1);

System.out.println ("Print str2:" + str2);}

}/* RUN result print str1:this are a test for immutable print str2:this is * *

In the example, although str1 called the substring () method, the STR1 value did not change. Similarly, this is true of other methods in the String class. Of course, if we put these two statements in the top case

C2.str = c2.str.substring (0,5);
C2.strbuff = C2.strBuff.append ("Change Strbuff clone");

Change it to the following:

C2.str.substring (0,5);
C2.strBuff.append ("Change Strbuff clone");

Remove the value of the process, C2.STR also can not be changed, our trick is revealed. But in the programming process only call

C2.str.substring (0,5);

Statement does not make any sense.

What you should know is that all the basic data types in Java have a corresponding class, like the int type for the integer class, the double type, and so on, and these classes are the same as the string class and are not allowed to change. In other words, all of the methods in these classes cannot change their own values. It also gives us a lot more choice when it comes to cloning a clone class. We can also weave our own classes into immutable classes.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.