Method 1 overloads the clone() method
The Object parent class has a clone() copy method, but it is of protected type. We need to override it and change it to public type. In addition, subclasses also need to implement the clonable interface to tell the JVM that this class can be copied.
Rewrite code
Let's modify the User class and Address class to implement the clonable interface to support deep copy.
/** * address */ public class Address implements Cloneable { private String city; private String country; // constructors, getters and setters @Override public Address clone() throws CloneNotSupportedException { return (Address) super.clone(); } }
/** * user */ public class User implements Cloneable { private String name; private Address address; // constructors, getters and setters @Override public User clone() throws CloneNotSupportedException { User user = (User) super.clone(); user.setAddress(this.address.clone()); return user; } }
It should be noted that super Clone () is actually a shallow copy, so when overriding the clone () method of the User class, the address object needs to call address clone() reassigns.
test case
@Test public void cloneCopy() throws CloneNotSupportedException { Address address = new Address("Hangzhou", "China"); User user = new User("Dashan", address); // call clone()Method for deep copy User copyUser = user.clone(); // Modify the value of the source object user.getAddress().setCity("Shenzhen"); // Check that the values of the two objects are different assertNotSame(user.getAddress().getCity(), copyUser.getAddress().getCity()); }
Method 2: Apache Commons Lang serialization
Java provides the ability of serialization. We can serialize the source object first, and then deserialize it to generate a copy object. However, the premise of using serialization is that the copied class (including its member variables) needs to implement the Serializable interface. Apache Commons Lang package encapsulates Java serialization, and we can use it directly.
Rewrite code
Let's modify the User class and Address class to implement the Serializable interface to support serialization.
/** * address */ public class Address implements Serializable { private String city; private String country; // constructors, getters and setters }
/** * user */ public class User implements Serializable { private String name; private Address address; // constructors, getters and setters }
test case
@Test public void serializableCopy() { Address address = new Address("Hangzhou", "China"); User user = new User("Dashan", address); // use Apache Commons Lang Serialization for deep copy User copyUser = (User) SerializationUtils.clone(user); // Modify the value of the source object user.getAddress().setCity("Shenzhen"); // Check that the values of the two objects are different assertNotSame(user.getAddress().getCity(), copyUser.getAddress().getCity()); }
Method 3: Gson serialization
Gson can serialize objects into JSON or deserialize JSON into objects, so we can use it for deep copy.
test case
@Test public void gsonCopy() { Address address = new Address("Hangzhou", "China"); User user = new User("Dashan", address); // use Gson Serialization for deep copy Gson gson = new Gson(); User copyUser = gson.fromJson(gson.toJson(user), User.class); // Modify the value of the source object user.getAddress().setCity("Shenzhen"); // Check that the values of the two objects are different assertNotSame(user.getAddress().getCity(), copyUser.getAddress().getCity()); }
Method 4 Jackson serialization
Similar to Jason, Jackson can serialize objects into JSON. The obvious difference is that the copied class (including its member variables) needs a default parameterless constructor.
Rewrite code
Let's modify the User class and Address class to implement the default parameterless constructor to support Jackson.
/** * user */ public class User { private String name; private Address address; // constructors, getters and setters public User() { } }
/** * address */ public class Address { private String city; private String country; // constructors, getters and setters public Address() { } }
test case
@Test public void jacksonCopy() throws IOException { Address address = new Address("Hangzhou", "China"); User user = new User("Dashan", address); // use Jackson Serialization for deep copy ObjectMapper objectMapper = new ObjectMapper(); User copyUser = objectMapper.readValue(objectMapper.writeValueAsString(user), User.class); // Modify the value of the source object user.getAddress().setCity("Shenzhen"); // Check that the values of the two objects are different assertNotSame(user.getAddress().getCity(), copyUser.getAddress().getCity()); }
summary
In addition to the first method of overriding clone, the other methods are implemented through serialization.
The scheme selection depends on whether the copied class (including its member variables) provides a deep copy constructor, whether it implements the Cloneable interface, whether it implements the Serializable interface, and whether it implements the default parameterless constructor. If you need to consider it in detail, you can refer to the following table:
Deep copy method
|
advantage
|
shortcoming
|
Override clone() method
|
1. The underlying implementation is simple
2. There is no need to introduce a third-party package
3. Low system overhead
|
1. The availability is poor. You may need to modify the clone() method every time you add a member variable
2. Copy classes (including their member variables) need to implement clonable interface
|
Apache.Commons.Lang serialization
|
1. High availability. There is no need to modify the copy method for adding member variables
|
1. The underlying implementation is complex
2. Apache Commons Lang third-party JAR package needs to be introduced
3. The copy class (including its member variables) needs to implement the Serializable interface
4. Serialization and deserialization have certain system overhead
|
Gson serialization
|
1. High availability. There is no need to modify the copy method for adding member variables
2. There are no requirements for copying classes, and there is no need to implement additional interfaces and methods
|
1. The underlying implementation is complex
2. The third-party JAR package of Gson needs to be introduced
3. Serialization and deserialization have certain system overhead
|
Jackson serialization
|
1. High availability. There is no need to modify the copy method for adding member variables
|
1. The underlying implementation is complex
2. Jackson third-party JAR package needs to be introduced
3. The copy class (including its member variables) needs to implement the default parameterless constructor
4. Serialization and deserialization have certain system overhead
|