Java object cloning and java cloning
I. Preface
Two days ago, I went to apply for a pen question from a company, which had the following programming questions:
How do you understand object cloning in Java?
At that time, I was overwhelmed. Although I wrote a lot of questions in accordance with the principle of leaving no blank, the results were wrong. Next, I will paste my errors below. Readers should not follow suit and make jokes. Then I came back and went back to the furnace again, and found that a blog of the great god was well explained. Therefore, many of the items here are reproduced and modified according to your own understanding.
The following is a link to the blogger.
2. Java object cloning
In java object-oriented programming, to copy referenced objects, these objects must be cloned. You can use the clone method to clone all reference types and objects. For a value-type instance, the "=" value assignment operator can copy the status of the source object to the target object in a verbatim manner. The author understands that, in the case of object cloning, we have copied this object, but the Copied object has not actually changed, we only need to operate on the cloned object without modifying the cloned object. (PS: the explanation is a bit messy, but I can understand it myself. For more easy-to-understand statements, please advise in the comment area !)
Iii. Cognitive Error in object cloning
Before talking about cloning objects, let's talk about copying variables:
int apples = 5; int pears = apples;
The above is the replication of variables, and not only the int type can be copied, but also the other seven original data types (boolean, char, byte, short, float, double. long.
However, for object replication (cloning), the situation is a bit complicated, because I have never touched it before, so it leads to some cognitive errors. I will post my cognitive mistakes below:
Package com. ygh. cloneObj;/*** Student class ** @ author night cold * @ version 1.1.1 */class Student {private int number; public int getNumber () {return number ;} public void setNumber (int number) {this. number = number ;}}/*** Test class ** @ author Administrator * @ version 1.1.1 */public class Test {public static void main (String args []) {// create the object Student stu_1 = new Student (); stu_1.setNumber (12345); // The object reference value is Student stu_2 = stu_1; System. out. println ("Student 1:" + stu_1.getNumber (); System. out. println ("Student 2:" + stu_2.getNumber ());}}
The output result of the above Code is as follows:
At this time, we may think that we have achieved the purpose of cloning, but this is not the case. We use facts to tell our errors. We will set the setNumber () of stu_2 () set the method to 54321 and paste the source code:
Package com. ygh. cloneObj;/*** Student class ** @ author night cold * @ version 1.1.1 */class Student {private int number; public int getNumber () {return number ;} public void setNumber (int number) {this. number = number ;}}/*** Test class ** @ author Administrator * @ version 1.1.1 */public class Test {public static void main (String args []) {// create the object Student stu_1 = new Student (); stu_1.setNumber (54321); // The object reference value is Student stu_2 = stu_1; System. out. println ("Student 1:" + stu_1.getNumber (); System. out. println ("Student 2:" + stu_2.getNumber ());}}
Output result:
At this time, we will find that both results are 54321.
At this time, we will find that we only set the value of stu_2, but the value of stu_1 also changes. This means that we have not achieved the purpose of object cloning. The following figure shows why this problem occurs:
We will find that we only assign the reference of stu_1 to the reference of stu_2. The two actually point to the same object, that is, we have not achieved the purpose of object cloning.
So how can we copy an object?
We can remember the source of all the classes of Object. It has 11 methods and two protected methods, one of which is the clone method.
Copy the cookbook to another place and decompress it. It contains all the source code. It is found that there is a method clone () with the access qualifier protected ():
/*Creates and returns a copy of this object. The precise meaning of "copy" may depend on the class of the object.The general intent is that, for any object x, the expression:1) x.clone() != x will be true2) x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements.3) x.clone().equals(x) will be true, this is not an absolute requirement.*/protected native Object clone() throws CloneNotSupportedException;
Taking a closer look, it is still a native method. We all know that the native method is non-Java-implemented code for Java programs to call, because Java programs run on JVM virtual machines, to access the underlying operating system, there is no way to do it. It can only be implemented in a language close to the operating system.
Because each class's direct or indirect parent class is an Object, they all contain the clone () method, but because this method is protected, it cannot be accessed outside the class.
To copy an object, you must overwrite the clone method.
4. Why do we need to clone objects?
Let's take a look at the question: why do we need to clone objects? Can't I create an object directly?
The answer is: the cloned object may contain some modified attributes, and the attributes of the new object are still the values at the time of initialization, therefore, when a new object is needed to save the "State" of the current object, the clone method is used. So I will assign the temporary attributes of this object to my new object one by one. Isn't that all right? Yes, but I don't have to worry about it. I have found through the source code above that clone is a native method, which is fast and implemented at the underlying layer.
When we wake up, the Common Object a = new Object (); Object B; B = a; in this form of code copying is reference, that is, the address of the Object in the memory, objects a and B still point to the same object.
The object assigned by the clone method exists independently from the original object.
5. How to clone the database?
First, we will introduce two different cloning methods,ShallowClone)AndDeep clone (DeepClone).
In Java, data types include value type (basic data type) and reference type. value types include int, double, byte, boolean, char, and other simple data types, reference types include classes, interfaces, arrays, and other complex types. The main difference between shortest cloning and deep cloning is whether copying of referenced member variables is supported. The following describes the two methods in detail.
The general steps are as follows ):
1.The replicated class must implement the Clonenable interface.(If not implemented, the CloneNotSupportedException exception will be thrown when the clone method is called.) This interface is a flag interface (excluding any methods)
2.Overwrite the clone () method and set the access modifier to public..Call the super. clone () method to obtain the required copy object.. (Native is the local method)
Next we will modify the class that was previously incorrectly recognized:
Class Student implements Cloneable {private int number; public int getNumber () {return number;} public void setNumber (int number) {this. number = number ;}@ Override public Object clone () {Student stu = null; try {stu = (Student) super. clone ();} catch (CloneNotSupportedException e) {e. printStackTrace ();} return stu;} public class Test {public static void main (String args []) {Student stu1 = new Student (); stu1.setNumber (12345 ); student stu2 = (Student) stu1.clone (); System. out. println ("Student 1:" + stu1.getNumber (); System. out. println ("Student 2:" + stu2.getNumber (); stu2.setNumber (54321); System. out. println ("Student 1:" + stu1.getNumber (); System. out. println ("Student 2:" + stu2.getNumber ());}}
The output result is as follows:
At this time, we can find that the object has been cloned, and two different references point to different objects. If you do not believe it, you can add a code at the end of the Code:
System.out.println(stu1 == stu2); // false
This indicates that the two references point to different objects.
However, the above Code only implements shallow replication. Next we will introduce the deep replication, and add an Address class to the class above:
Class Address {private String add; public String getAdd () {return add;} public void setAdd (String add) {this. add = add ;}} class Student implements Cloneable {private int number; private Address addr; public Address getAddr () {return addr;} public void setAddr (Address addr) {this. addr = addr;} public int getNumber () {return number;} public void setNumber (int number) {this. number = number ;}@ Override public Object clone () {Student stu = null; try {stu = (Student) super. clone ();} catch (CloneNotSupportedException e) {e. printStackTrace ();} return stu;} public class Test {public static void main (String args []) {Address addr = new Address (); addr. setAdd ("Hangzhou City"); Student stu1 = new Student (); stu1.setNumber (123); stu1.setAddr (addr); Student stu2 = (Student) stu1.clone (); System. out. println ("Student 1:" + stu1.getNumber () + ", address:" + stu1.getAddr (). getAdd (); System. out. println ("Student 2:" + stu2.getNumber () + ", address:" + stu2.getAddr (). getAdd ());}}
Result:
At first glance, there is no problem. Is that true?
Add the following code to the main method:
Addr. setAdd ("Xihu District"); System. out. println ("Student 1:" + stu1.getNumber () + ", address:" + stu1.getAddr (). getAdd (); System. out. println ("Student 2:" + stu2.getNumber () + ", address:" + stu2.getAddr (). getAdd ());
At this time, we will find that the output result is different from what we want:
What we hope is that the first sentence of the last two sentences is Hangzhou, and the second sentence is Xihu District. The reason for this is that the shallow copy only copies the reference of the addr variable and does not really open up another space. After copying the value, the reference is returned to the new object.
Therefore, in order to achieve a real copy object, rather than purely reference replication. We need to copy the Address class and modify the clone method. The complete code is as follows:
Package abc; class Address implements Cloneable {private String add; public String getAdd () {return add;} public void setAdd (String add) {this. add = add ;}@ Override public Object clone () {Address addr = null; try {addr = (Address) super. clone ();} catch (CloneNotSupportedException e) {e. printStackTrace () ;}return addr ;}} class Student implements Cloneable {private int number; private Address addr; public Address getAddr () {return addr;} public void setAddr (Address addr) {this. addr = addr;} public int getNumber () {return number;} public void setNumber (int number) {this. number = number ;}@ Override public Object clone () {Student stu = null; try {stu = (Student) super. clone (); // shallow copy} catch (CloneNotSupportedException e) {e. printStackTrace ();} stu. addr = (Address) addr. clone (); // return stu;} public class Test {public static void main (String args []) {Address addr = new Address (); addr. setAdd ("Hangzhou City"); Student stu1 = new Student (); stu1.setNumber (123); stu1.setAddr (addr); Student stu2 = (Student) stu1.clone (); System. out. println ("Student 1:" + stu1.getNumber () + ", address:" + stu1.getAddr (). getAdd (); System. out. println ("Student 2:" + stu2.getNumber () + ", address:" + stu2.getAddr (). getAdd (); addr. setAdd ("Xihu District"); System. out. println ("Student 1:" + stu1.getNumber () + ", address:" + stu1.getAddr (). getAdd (); System. out. println ("Student 2:" + stu2.getNumber () + ", address:" + stu2.getAddr (). getAdd ());}}View Code
Output result:
The above results are in line with our ideas.
Finally, let's take a look at one of the classes that implement the clone method in the API:
/*** Return a copy of this object. */public Object clone () {Date d = null; try {d = (Date) super. clone (); if (cdate! = Null) {d. cdate = (BaseCalendar. Date) cdate. clone () ;}} catch (CloneNotSupportedException e) {}// Won't happen return d ;}View Code
This class actually belongs to deep replication.
Vi. Shortest cloning and deep cloning 1. Shortest cloning
In the shortest clone, if the member variable of the prototype object is of the value type, copy it to the cloned object. If the member variable of the prototype object is of the reference type, copy the address of the referenced object to the cloned object, that is, the member variables of the prototype object and the cloned object point to the same memory address.
In simple terms, when an object is copied, only the member variables of its own and included value types are copied, but the Member objects of the reference type are not copied.
In JavaThe clone () method that overwrites the Object class can implement shortest cloning..
2. Deep cloning
In deep cloning, no matter whether the member variables of the prototype are value type or reference type, a copy is copied to the cloned object, deep clone copies all referenced objects of the prototype object to the cloned object.
Simply put, in deep cloning, all the member variables contained in the object will be copied in addition to the object itself being copied.
In JavaTo achieve deep cloning, you can useOverwrite the clone () method Implementation of the Object class.Serialization and other methods are supported..
(If the reference type also contains many reference types, or the class with the inner reference type contains the reference type, it will be very troublesome to use the clone method. In this case, we can use serialization to achieve deep object cloning.)
Serialization is the process of writing an object to the stream. The object written to the stream is a copy of the original object, and the original object still exists in the memory. The copy implemented by serialization not only copies the object itself, but also copies the referenced Member objects. Therefore, the object is written to a stream through serialization and then read from the stream, deep cloning is supported. Note that the class of the object that can be serialized must implement the Serializable interface; otherwise, the serialization operation cannot be implemented.
VII. Knowledge Extension
The code for the Cloneable interface and Serializable interface provided by Java is very simple. They are all empty interfaces. This empty interface is also called the ID interface, and there is no method definition in the ID interface, the function is to tell JRE whether the implementation classes of these interfaces have certain functions, such as whether cloning and serialization are supported.
VIII. Multi-layer cloning Solution
Public class Outer implements Serializable {private static final long serialVersionUID = 369285298572941L; // it is best to explicitly declare the ID public Inner inner; // Discription: [Deep replication method, all object attributes of the object must be serialized.] public Outer myclone () {Outer outer Outer = null; try {// serialize the object into a stream, because a copy of the object is written in the stream, and the original object still exists in JVM. Therefore, we can use this feature to implement the object's deep copy of ByteArrayOutputStream baos = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (baos); oos. writeObject (this); // serialize the stream to the object ByteArrayInputStream bais = new ByteArrayInputStream (baos. toByteArray (); ObjectInputStream ois = new ObjectInputStream (bais); outer = (Outer) ois. readObject ();} catch (IOException e) {e. printStackTrace ();} catch (ClassNotFoundException e) {e. printStackTrace () ;}return outer ;}}
The Inner must also implement Serializable; otherwise, serialization fails:
Public class Inner implements Serializable {private static final long serialVersionUID = 872390113366l; // it is best to explicitly declare ID public String name = ""; public Inner (String name) {this. name = name ;}@ Override public String toString () {return "Inner's name value:" + name ;}}
In this way, the two objects can exist completely independently in the memory space and do not affect each other's values.
IX. Summary
There are two methods to achieve object cloning:
1) Implement the Cloneable interface and override the clone () method in the Object class;
2) Implement the Serializable interface. Object serialization and deserialization can be used to achieve real deep cloning.
Note:Cloning Based on serialization and deserialization is not only a deep clone, but also a generic limitation to check whether the object to be cloned supports serialization. This check is completed by the compiler, it is not to throw an exception at runtime. This solution is obviously better than cloning an Object using the Object class clone method. Exposing a problem during compilation is always better than leaving the problem at runtime.