Creation of objects in Java
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?
- Create an object using the new operator
- 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.
Copy object or copy reference
In Java, code similar to the following is very common:
Person p = new person ("Zhang"); person P1 = P; SYSTEM.OUT.PRINTLN (P); System.out.println (p1);
When person p1 = P; After execution, is a new object created? First look at the print results:
[Email protected]
[Email protected]
As you can see, the printed address values are the same, and since the addresses are the same, it must be the same object. P and P1 are just references, and they all point to a person of the same object ("Zhang"). This phenomenon can be referred to as reference replication. (For reference and object differentiation, you can refer to my previous article why is string in Java immutable?) --string source analysis, in which a section describes the distinction between references and objects. After the execution of the above code is complete, the in-memory scenario looks like this:
And the following code is really a true clone of an object.
Person p = new person ("Zhang"); person P1 = (person) p.clone (); SYSTEM.OUT.PRINTLN (P); System.out.println (p1);
As you can see from the printout, the address of two objects is different, that is, creating a new object instead of assigning the address of the original object to a new reference variable:
[Email protected]
[Email protected]
When the above code finishes executing, the in-memory scenario looks like this:
deep Copy or shallow copy
In the example code above, there are two member variables in person, name and age, name is a string type, and age is an int type. The code is very simple, as follows:
Public classPersonImplementscloneable{Private intAge ; PrivateString name; PublicPerson (intAge , String name) { This. Age =Age ; This. Name =name; } PublicPerson () {} Public intGetage () {returnAge ; } PublicString GetName () {returnname; } @OverrideprotectedObject Clone ()throwsclonenotsupportedexception {return(person)Super. Clone (); }}
View Code
Since age is the basic data type, there is no doubt about its copy, just copy a 4-byte integer value. But name is a string type, it is just a reference, to a real string object, then there are two ways to copy it: directly copy the reference value of name in the source object to the Name field of the new object. Either create a new identical string object based on the string object that is pointed to in the original person object, and assign a reference to the new string object to the name field of the newly copied person object. These two copies are called Light and deep copies, respectively. The principle of deep copy and shallow copy is as follows:
The following is verified by code. If the address value of the name of the two person object is the same, the name of both objects points to the same string object, which is a shallow copy, and if the address value of the name of the two object is different, then a different string object is pointed to. That is, when the person object is copied, the string object referenced by name is also copied, that is, a deep copy. The verification code is as follows:
New Person (*, "Zhang"= (person) p.clone (); System.out.println ("P.getname (). Hashcode ():" + P.getname (). Hashcode ()); System.out.println ("P1.getname (). Hashcode ():" + P1.getname (). Hashcode ()); = P.getname (). Hashcode () = = P1.getname (). Hashcode ( )? "Clone is a shallow copy": "Clone is a deep copy"; SYSTEM.OUT.PRINTLN (result);
View Code
Printing results are:
P.getname (). Hashcode (): 115864556
P1.getname (). Hashcode (): 115864556
clone is a shallow copy . Therefore, the Clone method performs a shallow copy, which should be noted in writing the program.
overwrite the Clone method in object to achieve a deep 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, which is a shallow copy, verify again with the following code:
Static classBodyImplementscloneable{ Publichead Head; PublicBody () {} PublicBody (head head) { This. Head =Head;} @OverrideprotectedObject Clone ()throwsclonenotsupportedexception {return Super. Clone (); } } Static classHead/*implements Cloneable*/{ PublicFace face ; PublicHead () {} PublicHead (face face) { This. face =Face ;} } Public Static voidMain (string[] args)throwsclonenotsupportedexception {Body Body=NewBody (NewHead ()); Body body1=(Body) Body.clone (); System.out.println ("BODY = = Body1:" + (BODY = =body1)); System.out.println ("Body.head = = Body1.head:" + (Body.head = =body1.head)); }
View Code
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.
Static classBodyImplementscloneable{ Publichead Head; PublicBody () {} PublicBody (head head) { This. Head =Head;} @OverrideprotectedObject Clone ()throwsclonenotsupportedexception {Body newbody= (Body)Super. Clone (); Newbody.head=(Head) Head.clone (); returnNewbody; } } Static classHeadImplementscloneable{ PublicFace face ; PublicHead () {} PublicHead (face face) { This. face =Face ;} @OverrideprotectedObject Clone ()throwsclonenotsupportedexception {return Super. Clone (); } } Public Static voidMain (string[] args)throwsclonenotsupportedexception {Body Body=NewBody (NewHead ()); Body body1=(Body) Body.clone (); System.out.println ("BODY = = Body1:" + (BODY = =body1)); System.out.println ("Body.head = = Body1.head:" + (Body.head = =body1.head)); }
View Code
Printing results are:
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)
Static classBodyImplementscloneable{ Publichead Head; PublicBody () {} PublicBody (head head) { This. Head =Head;} @OverrideprotectedObject Clone ()throwsclonenotsupportedexception {Body newbody= (Body)Super. Clone (); Newbody.head=(Head) Head.clone (); returnNewbody; } } Static classHeadImplementscloneable{ PublicFace face ; PublicHead () {} PublicHead (face face) { This. face =Face ;} @OverrideprotectedObject Clone ()throwsclonenotsupportedexception {return Super. Clone (); } } Static classface{} Public Static voidMain (string[] args)throwsclonenotsupportedexception {Body Body=NewBody (NewHead (NewFace ())); 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)); }
View Code
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:
Static classHeadImplementscloneable{ PublicFace face ; PublicHead () {} PublicHead (face face) { This. face =Face ;} @OverrideprotectedObject Clone ()throwsclonenotsupportedexception {//return Super.clone ();Head Newhead = (head)Super. Clone (); Newhead.face= (face) This. Face.clone (); returnNewhead; } } Static classFaceImplementscloneable{@OverrideprotectedObject Clone ()throwsclonenotsupportedexception {return Super. Clone (); } }
View Code
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.
written in the last
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. For the creation of immutable objects, I will explain in the subsequent articles, please look forward to.
Goto: A detailed description of the Clone () method in Java