How to Make a Deep Copy of an Object in Java

In this article, we will discuss as of how to make a deep copy of an object in Java.

 

Introduction

While creating a copy of Java objects, we have the following two options for creating a copy

  1. A shallow copy.
  2. A deep copy

Shallow copy approach only copy field values, this approach is not complete as the copy may depend on the original object. The deep 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 a copy constructor for deep copy, we will create a constructor in our model class as follows

//Copy Constructor
public Order(Order order){
   this(order.getOrderNumber(),order.getOrderAmount(),order.getOrderStatus());
}
//Copy Constructor
public Customer(Customer customer) {
this(customer.getFirstName(),customer.getFirstName(),new Order(customer.getOrder()));
}

Test Case::

public class CopyConstructorTest {

@Test
public 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 the Object class.Make sure to override this method as public.We also need to use Cloneable, to the classes to show that the classes are actually cloneable.

@Override
public Order clone(){
  try {
        return (Order) super.clone();
      }catch (CloneNotSupportedException e) {
         return new Order(this.orderNumber,this.orderAmount,this.orderStatus);
     }
}
//Customer
@Override
public 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 Copy Constructor 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 use Apache Commons Lang SerializationUtils class for a deep copy of an object in Java.

 

2.1. Apache Common Lang

Apache Commons Lang comes with SerializationUtils.clone() method for a deep copy of an object. It expects all classes in the hierarchy to implement Serializable interfaces else SerializableException thrown by the system.

public class SerializationUtilsTest {

@Test
public 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 a deep copy of an object in Java. We covered different options for creating a deep copy of the object and why to prefer a deep copy over a shallow copy.

2 thoughts on “How to Make a Deep Copy of an Object in Java”

Comments are closed.