Java programming implementation object clone (copy) code details, java details
Clone: It's amazing to hear that the world's first cloned goat Dolly uses the Cell Nucleus transplantation technology to cultivate new individuals in adult cells of mammals. In fact, there is also the concept of cloning in Java, that is, copying objects.
This article will try to introduce some cloning and some in-depth issues in Java, hoping to help you better understand cloning.
Suppose you want to copy a simple variable. Simple:
int apples = 5; int pears = apples;
The other seven types of raw data (boolean, char, byte, short, float, and double. long) are also applicable to this type of data.
However, if you copy an object, the situation is complicated.
Assume that I am a beginner, and I will write it like this:
Class Student {private int number; public int getNumber () {return number;} public void setNumber (int number) {this. number = number ;}}public class Test {public static void main (String args []) {Student stu1 = new Student (); stu1.setNumber (12345); Student stu2 = stu1; system. out. println ("Student 1:" + stu1.getNumber (); System. out. println ("Student 2:" + stu2.getNumber ());}}
Result:
Student
Student
Here we customize a student class, which has only one number field.
We created a new student instance and assigned the value to stu2. (Student stu2 = stu1 ;)
Let's take a look at the printed results. As a newbie, I patted my chest, but the object was not copied,
Is that true?
We tried to change the number field of stu2 instance, and then print the result to see:
Stu2.setNumber (54321); System. out. println ("Student 1:" + stu1.getNumber (); System. out. println ("Student 2:" + stu2.getNumber ());
Result:
Student 54321
Student 54321
This is strange. Why does STUDENT 2's student ID change?
The reason is (stu2 = stu1. This statement is used to assign the reference value of stu1 to stu2,
In this way, stu1 and stu2 point to the same object in the memory heap.
So how can we copy an object?
Whether to remember the King Object of all kinds. 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.
The first statement ensures that the cloned object will be allocated with a separate memory address.
The second declaration indicates that the original and cloned object should have the same class type, but it is not mandatory.
The third statement indicates that the original and cloned objects should be used in equal equals () methods, but it is not mandatory.
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.
Why clone?
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.
How to clone
First, we will introduce two different cloning methods: ShallowClone and 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 copied class needs to implement the Clonenable interface (if not implemented, the CloneNotSupportedException exception will be thrown when the clone method is called). This interface is marked as an interface (excluding any methods)
2. overwrite the clone () method and set the access modifier to public. Method to obtain the required copy object. (Native is the local method)
Next we will transform the above method:
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 ());}}
Result:
Student
Student
Student
Student 54321
If you do not believe that these two objects are not the same, you can look at this sentence:
System.out.println(stu1 == stu2); // false
The above copy is called a shortest clone.
There is also a slightly complex deep replication:
We add an Address class to the student class.
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:
Student, address: Hangzhou City
Student, address: Hangzhou City
At first glance, there is no problem. Is that true?
We tried to change the addr instance address in 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 ());
Result:
Student:; Address: Hangzhou student; Address: West Lake District student
This is strange. How have the addresses of both students changed?
The reason 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 ());}}
Result:
Student, address: Hangzhou City
Student, address: Hangzhou City
Student, address: Xihu District
Student, address: Hangzhou City
In this way, the 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:
Java. util. Date:
/** * 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; }
This class actually belongs to deep replication.
Shortest cloning and deep cloning
1. 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 Java, you can perform shortest cloning by overwriting the Object class clone () method.
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 Java, if you need to implement deep cloning, You can implement it by overwriting the clone () method of the Object class, or by Serialization.
(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.
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.
Multi-layer cloning
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.
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.
Summary
There are two methods to achieve object cloning:
Required bytes 1). Implement the Cloneable interface and override the clone () method in the Object class;
2). implements the Serializable interface, and achieves cloning through object serialization and deserialization, which can realize 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.
The above is all the details about the Java programming implementation object clone (copy) code. I hope it will be helpful to you. If you are interested, you can continue to refer to other related topics on this site. If you have any shortcomings, please leave a message.