Clone is copied as its name implies, and in the Java language, the Clone method is called by the object, so the object is copied. The so-called Replication object, the first to allocate a source object and the same size of space, in this space to create a new object. So in the Java language, there are several ways to create objects?
1. Create an object using the new operator
2. Copy an object using the Clone method
So what are the similarities and differences between these two approaches? The new operator is intended to allocate memory. When the program executes to the new operator, it first looks at the type following the new operator because it knows the type to know how much memory space to allocate. After allocating memory, call the constructor, populate the object's fields, this step is called the initialization of the object, after the construction method is returned, an object is created, you can publish his reference (address) to the outside, you can use this reference to manipulate the object externally. and clone in the first step is similar to new, is to allocate memory, when calling the Clone method, the allocated memory and the source object (that is, the object called the Clone method) is the same, and then use the corresponding fields in the original object, populate the new object's domain, after the completion of the Clone method returns, A new, identical object is created, and the reference to the new object can be published externally. "A detailed explanation of the Clone method in Java"
Copy of Reference
//引用拷贝 private static void copyReferenceObject(){ Person p = new Person(23, "zhang"); Person p1 = p; System.out.println(p); System.out.println(p1); }
Here are the results printed:
[Email protected]
[Email protected]
As you can see, the result of printing is the same, that is, the reference to the two is the same object, and no new object is created. So to differentiate between reference copies and object copies, the following is an object copy.
Shallow copy
A shallow copy is a bitwise copy of an object that creates a new object with an exact copy of the original object's property values. If the property is a base type, the copy is the value of the base type, and if the property is a memory address (reference type), the memory address is copied, so if one of the objects changes the address, it will affect the other object.
The class that implements the object copy must implement the Cloneable interface and overwrite the Clone () method.
Persion class:
Package com.yaolong.clone;PublicClassPersonImplementscloneable{Private Integer age;Privateint age;The Ali specification stipulates that the attributes in the Pojo class are forced to use the wrapper type, which is just a testprivate String name;PublicPerson (Integer age, String name) {Super ();This.age = age;THIS.name = name; }Public IntegerGetage () {return age; }Publicvoidsetage (Integer age) {this.age = Age;} public String getname () {return Name } public void setName (String name) { this.name = name;} @Override public String ToString () {return super.tostring ();} @Override protected Object clone () throws clonenotsupportedexception {return Super.clone (); }}
//对象拷贝 private static void copyRealObject() throws CloneNotSupportedException{ Person p = new Person(23, "zhang"); Person p1 = (Person) p.clone(); System.out.println(p); System.out.println(p1); }
Here are the results printed:
[Email protected]
[Email protected]
As you can see, the object addresses are different, so a copy is implemented.
However, there is still a problem, that is, the person class has a string type of reference object name, is it really copied past, or still refer to the same name object, on the basis of the above code, we continue to print:
System.out.println("pName:"+p.getName().hashCode()); System.out.println("p1Name:"+p1.getName().hashCode());
Here are the results printed:
pname:115864556
p1name:115864556
As you can see, the Name property of the two still points to the same object. The above intentionally changed the Age property to an int base type because the base data type does not have a reference problem.
This is actually a typical shallow copy:
Deep-Copy Memory graph:
From the above, clone inherited from object is the default implementation of a shallow copy.
Deep copy
A deep copy copies all of the attributes and copies the dynamically allocated memory that the attribute points to. A deep copy occurs when the object is copied along with the object it refers to. A deep copy is slower and more expensive than a shallow copy.
Now in order to make a deep copy of the Clone object, it is necessary to clonable the interface, overwrite and implement the Clone method, except to invoke the Clone method in the parent class to get the new object, and also clone the reference variable in the class. If you only use the default Clone method in object, it is a shallow copy.
StaticClassBodyImplementscloneable{Public head head;Public Body () {}Public Body (head head) {This.head = head;} @OverrideProtected Object Clone () throws Clonenotsupportedexception {ReturnSuper.clone (); }}Staticclass head/* implements Cloneable*/{public face face; public Head () {} public Head (face face) { this.face = Face;}} public static void Main (String[] args) throws Clonenotsupportedexception {Body BODY = new Body ( New Head ()); Body body1 = (body) body.clone (); System.out.println ( "BODY = = Body1:" + (BODY = = body1)); System.out.println ( "Body.head = = Body1.head:" + (Body.head = = Body1.head);}
In the above code, there are two main classes, body and face respectively, in the body class, a face object is combined. When you clone a Body object, it combines a face object with only a shallow copy.
Printing results can verify the conclusion:
BODY = = Body1:false
Body.head = = Body1.head:true
If you want to make a deep copy of the body object in clone, then in the body's clone method, the head object referenced by the source object is also clone a copy.
StaticClassBodyImplementscloneable{Public head head;Public Body () {}Public Body (head head) {this.head = head;} @OverrideProtected ObjectClone () throws Clonenotsupportedexception {Body Newbody = (body) Super.Clone (); Newbody.head = (head) head.Clone ();return newbody; }}StaticClassHeadImplementscloneable{public face face; public Head () {} public Head (face face) {this.face = face;} @ Override protected Object clone () throws clonenotsupportedexception {return super. Clone (); }} public static void Main (string[] args) throws clonenotsupportedexception {Body BODY = new Body (new Head ()); Body body1 = (body) body. clone (); System.out.println ( "BODY = = Body1:" + (BODY = = body1)); System.out.println ( "Body.head = = Body1.head:" + (Body.head = = Body1.head);}
Print Result: BODY = = Body1:false
Body.head = = Body1.head:false
Thus, the head reference within body and body1 points to a different head object, which means that at the same time as the Clone body object, it also copies the head object it refers to and makes a deep copy.
Is it really a deep copy?
The following conclusions can be drawn from the previous section: If you want to make a deep copy of an object, this object must implement the Cloneable interface, implement the Clone method, and, within the Clone method, copy the other objects referenced by the object to a clone, This requires that the referenced object must also implement the Cloneable interface and implement the Clone method.
Then, according to the above conclusion, the body class combines the head class, and the head class combines the face class, in order to deep copy the body class, must be in the Body class clone method will also copy the Head class, but in the copy head class, the default is to perform a shallow copy, That is, the face object combined in the head is not copied. The verification code is as follows: (here is the code for the face class only, but to be consistent in reading, to avoid losing contextual information, or to give the entire program, the whole program is very brief)
StaticClassBodyImplementscloneable{Public head head;Public Body () {}Public Body (head head) {this.head = head;} @OverrideProtected ObjectClone () throws Clonenotsupportedexception {Body Newbody = (body) Super.Clone (); Newbody.head = (head) head.Clone ();return newbody; }}StaticClassHeadImplementscloneable{Public face face;Public Head () {}Public Head, {this.face = face;} @OverrideProtected ObjectClone () throws Clonenotsupportedexception {return super. clone ();}} static class face{}public static void Main ( String[] args) throws Clonenotsupportedexception {Body BODY = new Body (new Head (new Face ())); Body body1 = (body) body. clone (); System.out.println ( "BODY = = Body1:" + (BODY = = body1)); System.out.println ( "Body.head = = Body1.head:" + (Body.head = = Body1.head)); System.out.println ( "Body.head.face = = Body1.head.face:" + (Body.head.face = = body1.head.face))}
Printing results are:
BODY = = Body1:false
Body.head = = Body1.head:false
Body.head.face = = Body1.head.face:true
So, is this a deep copy of the body object? In fact, it should be a deep copy, since the other objects referenced within the Body object (currently only head) are copied, meaning that the head reference within two separate body objects has pointed to a separate two head object. However, for the two head objects, they point to the same face object, which means that two body objects still have a certain connection and are not completely independent of each other. This should be said to be an incomplete deep copy.
How to make a thorough deep copy
For the above example, how can you ensure that two body objects are completely independent? As long as the head object is copied, the face object will be copied a copy of it. This requires that the face class also implement the Cloneable interface, implement the Clone method, and copy the face object it refers to in the Clone method of the head object. The modified part of the code is as follows:
StaticClassHeadImplementscloneable{Public face face;public Head () {} public Head (face face) {this.face = face;} @ Override protected Object clone () throws clonenotsupportedexception {//return super.clone (); Head Newhead = (head) Super. clone (); newhead.face = (face) this.face. clone (); return Newhead;} static class face implements Cloneable{@Override protected Object clone () throws Clonenotsupportedexception { Span class= "Hljs-keyword" >return super. clone ()}}
Running the above example again, the results are as follows: BODY = = Body1:false
Body.head = = Body1.head:false
Body.head.face = = Body1.head.face:false
This says that the name two body is completely independent, the face object that they indirectly refer to has been copied, that is, refers to the independent face object.
And so on, if the face object also references other objects, such as mouth, if it is not processed, the body object is copied and referenced to the same mouth object by a first-level reference. Similarly, if you want the body to be completely independent on the reference chain, you can only explicitly make the mouth object copy. Here, you can get the following conclusion: If you want to copy an object and the source object is completely independent of each other, then each level of object on the reference chain must be explicitly copied. Therefore, it is very troublesome to create a thorough deep copy, especially if the reference relationship is very complex, or if a third party object is referenced at some level of the reference chain, and the object does not implement the Clone method, then all referenced objects after it are shared. For example, if the face class referenced by the head is a class in a third-party library, and the Cloneable interface is not implemented, then all objects after the face are referenced together by the two body objects before and after the copy. Assume that the mouth object is assembled inside a face object, and that the tooth object is combined inside the mouth object.
Cloning may not be very frequent in the development of a project, but distinguishing between deep and shallow copies gives us a deeper understanding of how Java memory is structured and run. As for thorough deep copy, it is almost impossible to achieve, for reasons already described in the previous section. Deep and deep copies, when creating immutable objects, can have subtle effects on the program and may determine whether immutable objects we create are really immutable. An important application of clone is also used for the creation of immutable objects.
Java shallow copy and deep copy