We know that Java The Cloneable interface exists, and the classes that implement it all have the ability to be copied. At the same time, the copy is done in memory, which is faster in performance than the object generated directly by new. Especially in the generation of large objects, the performance improvement is very obvious. However, we know that copy can be divided into deep copy and shallow copy, but shallow copy has the problem of incomplete copy of object attributes. For deep and shallow copies, please refer to here: Shallow and deep copies of java
1. Shallow copy problem
Let's first look at the following code:
-
public class Person implements Cloneable{
-
-
private String name;
-
-
-
private Email email;
-
-
public String getName() {
-
return name;
-
}
-
-
public void setName(String name) {
-
this.name = name;
-
}
-
-
public Email getEmail() {
-
return email;
-
}
-
-
public void setEmail(Email email) {
-
this.email = email;
-
}
-
-
public Person(String name,Email email){
-
this.name = name;
-
this.email = email;
-
}
-
-
public Person(String name){
-
this.name = name;
-
}
-
-
protected Person clone() {
-
Person person = null;
-
try {
-
person = (Person) super.clone();
-
} catch (CloneNotSupportedException e) {
-
e.printStackTrace();
-
}
-
-
return person;
-
}
-
}
-
-
public class Client {
-
public static void main(String[] args) {
-
-
Email email = new Email("Please attend the meeting.","Please contact today 12:30 Attend the meeting in Conference Room 2...");
-
-
Person person1 = new Person("Zhang San",email);
-
-
Person person2 = person1.clone();
-
person2.setName("Li Si");
-
Person person3 = person1.clone();
-
person3.setName("Wang Wu");
-
-
System.out.println(person1.getName() + "The content of the email is:" + person1.getEmail().getContent());
-
System.out.println(person2.getName() + "The content of the email is:" + person2.getEmail().getContent());
-
System.out.println(person3.getName() + "The content of the email is:" + person3.getEmail().getContent());
-
}
-
}
-
--------------------
-
Output:
-
The content of Zhang San's e-mail is: Please contact today.12:30Attend the meeting in Conference Room 2...
-
Li Si's e-mail content is: Please contact today12:30Attend the meeting in Conference Room 2...
-
Wang Wu's e-mail content is: Please contact today12:30Attend the meeting in Conference Room 2...
In this application, we first define an email and send it to three people, Zhang San, Li Si and Wang Wu. Because they use the same email and have different names, we use Zhang San to copy Li Si and Wang Wu objects and change their names. There's nothing wrong with the program up to this point, but if we need Zhang San to arrive 30 minutes in advance, we can modify the contents of the mail.
-
public class Client {
-
public static void main(String[] args) {
-
-
Email email = new Email("Please attend the meeting.","Please contact today 12:30 Attend the meeting in Conference Room 2...");
-
-
Person person1 = new Person("Zhang San",email);
-
-
Person person2 = person1.clone();
-
person2.setName("Li Si");
-
Person person3 = person1.clone();
-
person3.setName("Wang Wu");
-
-
person1.getEmail().setContent("Please contact today 12:00 Attend the meeting in Conference Room 2...");
-
-
System.out.println(person1.getName() + "The content of the email is:" + person1.getEmail().getContent());
-
System.out.println(person2.getName() + "The content of the email is:" + person2.getEmail().getContent());
-
System.out.println(person3.getName() + "The content of the email is:" + person3.getEmail().getContent());
-
}
-
}
Here, we also use Zhang San as the object to realize the copy of Li Si and Wang Wu. Finally, we change the content of Zhang San's e-mail to: Please attend the meeting with today's 12:00 to Conference Room 2.... But the result is:
-
The content of Zhang San's e-mail is: Please attend the meeting from 12:00 to Conference Room 2 today.
-
Li Si's e-mail content is: Please attend the meeting from 12:00 to Conference Room 2 today.
-
Wang Wu's e-mail message is: Please attend the meeting from 12:00 to Conference Room 2 today.
Here we wonder why Li Si and Wang Wu's e-mail content has changed too. It would be advisable for them to arrive 30 minutes earlier!
In fact, the key to the problem lies in the clone() method, which we know uses the clone() method of Object class, but there is a flaw in this method. It does not copy all the attributes of the object, but selectively copies. The basic rules are as follows:
1. Basic types
If a variable is of a very basic type, copy its values, such as int, float, etc.
2. Objects
If a variable is an instance object, copy its address reference, that is to say, the new object and the original object are public instance variables.
String string
If the variable is a String string, copy its address reference. But when modified, it will regenerate a new string from the string pool, and the original Purple Capital object will remain unchanged.
Based on the above rules, we can easily find the problem. They share an object. If Zhang San modifies the content of the email, Li Si and Wang Wu will also modify it, so the above situation will occur. In this case, we can still solve the problem by creating a new object in the clone() method and then referring to it by Zhang San.
-
protected Person clone() {
-
Person person = null;
-
try {
-
person = (Person) super.clone();
-
person.setEmail(new Email(person.getEmail().getObject(),person.getEmail().getContent()));
-
} catch (CloneNotSupportedException e) {
-
e.printStackTrace();
-
}
-
-
return person;
-
}
Therefore, shallow copy is only a simple copy mechanism provided by Java, which is not easy to use directly.
There is still a problem with the above solution. If there are a large number of objects generated by copying in our system, if we write a clone() method for each class, we will need to make deep copies and create a large number of new objects, this project is very large. Here we can use serialization to achieve the copy of objects.
2. Implementing object copy by serialization
How to use serialization to complete object copy? It is easy to copy byte stream in memory. Write the parent object into a byte stream and read it out from the byte stream so that a new object can be created, and there is no problem of reference sharing between the new object and the parent object, so that the deep copy of the object can be realized.
-
public class CloneUtils {
-
@SuppressWarnings("unchecked")
-
public static <T extends Serializable> T clone(T obj){
-
T cloneObj = null;
-
try {
-
-
ByteArrayOutputStream out = new ByteArrayOutputStream();
-
ObjectOutputStream obs = new ObjectOutputStream(out);
-
obs.writeObject(obj);
-
obs.close();
-
-
-
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
-
ObjectInputStream ois = new ObjectInputStream(ios);
-
-
cloneObj = (T) ois.readObject();
-
ois.close();
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
return cloneObj;
-
}
-
}
Objects using the tool class must implement the Serializable interface, otherwise there is no way to achieve cloning.
-
public class Person implements Serializable{
-
private static final long serialVersionUID = 2631590509760908280L;
-
-
..................
-
//clone() removal method
-
-
}
-
-
public class Email implements Serializable{
-
private static final long serialVersionUID = 1267293988171991494L;
-
-
....................
-
}
Therefore, the clone() method can be implemented by using the tool class as long as the Serializable interface is implemented, without inheriting the Cloneable interface.
-
public class Client {
-
public static void main(String[] args) {
-
-
Email email = new Email("Please attend the meeting.","Please contact today 12:30 Attend the meeting in Conference Room 2...");
-
-
Person person1 = new Person("Zhang San",email);
-
-
Person person2 = CloneUtils.clone(person1);
-
person2.setName("Li Si");
-
Person person3 = CloneUtils.clone(person1);
-
person3.setName("Wang Wu");
-
person1.getEmail().setContent("Please contact today 12:00 Attend the meeting in Conference Room 2...");
-
-
System.out.println(person1.getName() + "The content of the email is:" + person1.getEmail().getContent());
-
System.out.println(person2.getName() + "The content of the email is:" + person2.getEmail().getContent());
-
System.out.println(person3.getName() + "The content of the email is:" + person3.getEmail().getContent());
-
}
-
}
-
-------------------
-
Output:
-
The content of Zhang San's e-mail is: Please contact today.12:00Attend the meeting in Conference Room 2...
-
Li Si's e-mail content is: Please contact today12:30Attend the meeting in Conference Room 2...
-
Wang Wu's e-mail content is: Please contact today12:30Attend the meeting in Conference Room 2...
-