How to Make a Deep Copy of an Object in Java
In this article, we will discuss as of how to make adeep copy of an object in Java.
Introduction
While creating a copy of Java objects, we have the following two options for creating a copy
- Ashallow copy.
- Adeep copy
Shallow copy approach only copy field values, this approach is not complete as the copy may depend on the original object. Thedeep copy approach in Java will copy the entire object tree and thus make this copy independent from the original object.In this article, we will focus on a deep copy of an object in Java.Deep cloning is closely related to Java serialization.
1. Deep Copy
Deep copy technique copies each mutable object in the object graph recursively. The object created through deep copy is not dependent upon the original object. We will cover few different options to make a deep copy of an object in Java.
1.1 Sample Model Classes
public class Order implements Serializable{private String orderNumber;private double orderAmount;private String orderStatus;//constructors, getters and setters}public class Customer implements Serializable {private String firstName;private String lastName;private Order order;//constructors, getters and setters}
1.2 Copy Constructor
To create acopy constructor for deep copy, we will create a constructor in our model class as follows
//Copy Constructorpublic Order(Order order){ this(order.getOrderNumber(),order.getOrderAmount(),order.getOrderStatus());}//Copy Constructorpublic Customer(Customer customer) {this(customer.getFirstName(),customer.getFirstName(),new Order(customer.getOrder()));}Test Case::
public class CopyConstructorTest {@Testpublic void testCopyConstructor(){ Order order = new Order("12345", 100.45, "In Progress"); Customer customer = new Customer("Test", "CUstomer", order); Customer customerCopy = new Customer(customer); order.setOrderStatus("Shipped"); assertNotEquals(customer.getOrder().getOrderStatus(), customerCopy.getOrder().getOrderStatus()); }}
1.3 Cloneable Interface
The second approach is to use clone method available in theObject class.Make sure to override this method as public.We also need to use Cloneable, to the classes to show that the classes are actuallycloneable.
@Overridepublic Order clone(){ try { return (Order) super.clone(); }catch (CloneNotSupportedException e) { return new Order(this.orderNumber,this.orderAmount,this.orderStatus); }}//Customer@Overridepublic Customer clone(){Customer customer =null;try { customer = (Customer) super.clone(); }catch (CloneNotSupportedException e) { customer = new Customer(this.firstName,this.lastName,this.order); } customer.order=this.order.clone(); return customer;}[pullquote align=”normal”]It is very hard to implement cloning with Cloneable right, and the effort is not worth it.For more detail read CopyConstructor versus Cloning[/pullquote]
1.4. Deep Copy using Serialization
public class JavaDeepCloneBySerialization {public static void main(String[] args) { Order order = new Order("12345", 100.45, "In Progress"); Customer customer = new Customer("Test", "CUstomer", order); Customer cloneCustomer = deepClone(customer); order.setOrderStatus("Shipped"); System.out.println(cloneCustomer.getOrder().getOrderStatus());}public static T deepClone(T object){ try { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(object); ByteArrayInputStream bais = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); ObjectInputStream objectInputStream = new ObjectInputStream(bais); return (T) objectInputStream.readObject(); } catch (Exception e) { e.printStackTrace(); return null; } }}
2. Deep Copy Using External Libraries
Java build in mechanism provided a good support for the deep copy of an object, however, we can have a certain limitation
- We do not own source code and it is not possible to add those additional constructors.
- Object hierarchy is complex and needs complex logic to handle all use cases.
For all such cases, we can useApache Commons Lang SerializationUtils class for adeep copy of an object in Java.
2.1. Apache Common Lang
Apache Commons Lang comes with SerializationUtils.clone() method for adeep copy of an object. It expects all classes in the hierarchy to implement Serializable interfaces elseSerializableException thrown by the system.
public class SerializationUtilsTest {@Testpublic void testDeepClone(){ Order order = new Order("12345", 100.45, "In Progress"); Customer customer = new Customer("Test", "Customer", order); Customer cloneCustomer = SerializationUtils.clone(customer); order.setOrderStatus("Shipped"); assertNotEquals(customer.getOrder().getOrderStatus(), cloneCustomer.getOrder().getOrderStatus());}}
Summary
In this post, we discussed how to make adeep copy of an object in Java. We covered different options for creating adeep copy of the objectand why to prefer a deep copy over a shallow copy.
