In this post, we will discuss following items.

  • What is object cloning in Java?
  • How to implement cloning in Java?
  • What is Cloneable interface and its main flaw?
  • Shallow Cloning.
  • Deep Cloning.
  • Alternate to Cloning.

What is object cloning in Java?

Object cloning is the process of creating exact copy of that object. To do this, there are two pre-requisite in Java:

1) implement Cloneable interface

2) and, override the clone() defined in java.lang.Object class.

The clone() is defined in java.lang.Object class and have protected access by default. You need to set its visibility to public by overriding it, so that you will be able to call this method from outside the class overriding it.

General contract of clone()

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:

x.clone() != x will be true, and that the expression x.clone().getClass() == x.getClass() will be true, but these are not absolute requirements.

While it is typically the case that x.clone().equals(x) will be true, this is not an absolute requirement.

No constructors are called on cloned object.

What is Cloneable interface and its main flaw?

Cloneable is marker interface. It's main flaw is that it lacks clone() method. Normally, interface means defining contracts for its implementing classes. But, here it just determines the behaviour of Object class's clone(). If presents, then calling clone method will return the field-by-field copy of that object; otherwise will throws CloneNotSupportedException.

Shallow Cloning

It is the field-by-field copy of that object. The implementation is pretty straightforward. Implement the Cloneable interface and override clone() from Object class.

Let's see this by code snippet.

public class Address implements Cloneable {
  private String streetAddress;
  private String city;
  private String state;
 
  public Address() {
  
  }
  //getters/ setters/ toString/ hashCode/ equals

  @Override
  public Address clone() throws CloneNotSupportedException {
    //Since no immutable object are there we will use shallow cloning only
    return (Address)super.clone();
  }
}

public class Employee implements Cloneable {
  private long id;
  private String name;
  private Address address;
 
  public Employee() {
  
  }
  // getters/ setters/ toString/ hashCode/ equals

  @Override
  public Employee clone() throws CloneNotSupportedException {
    return (Employee)super.clone();
  }
}
public class ShallowCloneExample {
  public static void main(String[] args) throws CloneNotSupportedException {
    Employee employee = new Employee(1, "Gaurav", new Address("Sector 37C", "Chandigarh", "India"));
    Employee shallowClone = employee.clone();
    employee.getAddress().setCity("Hoshiarpur");
    // should return false but returning true
    System.out.println(employee.getAddress().equals(shallowClone.getAddress()));
  }
}

In the above code snippet, Employee class clone() method called the super.clone() i.e. Object class's clone() method is called. The only problem in case of shallow cloning is when you have composed of Objects in your class. If you change anything in shallow cloned object reference, it will be reflected in original object reference as well.

When can we use shallow cloning

If all the instance fields are either primitive or Immutable object type, then shallow cloning is recommended.

Deep cloning

When you recursively clone each and every instance field of that object. Let's understand this by example.

public class Employee implements Cloneable {
  private long id;
  private String name;
  private Address address;
 
  public Employee() {
  
  }

  // getter/setters/toString/ equals/ hashCode

  @Override
  public Employee clone() throws CloneNotSupportedException {
    Employee cloned = (Employee) super.clone();
  
    if (this.address == null) {
      cloned.setAddress(null);
    }
    else {
      cloned.setAddress(this.address.clone());
    }
  
    return cloned;
  }
}


public class Address implements Cloneable {
  private String streetAddress;
  private String city;
  private String state;
 
  public Address() {
  }

  // getters/setters/toString/ hashCode/ equals

  @Override
  public Address clone() throws CloneNotSupportedException {
    //Since no immutable object are there we will use shallow cloning only
    return (Address)super.clone();
  }
}
public class DeepCloneExample {
  public static void main(String[] args) throws CloneNotSupportedException {
    Employee employee = new Employee(1, "Gaurav", new Address("Sector 37C", "Chandigarh", "India"));
    Employee deepClone = employee.clone();
    employee.getAddress().setCity("Hoshiarpur");
    // should return false
    System.out.println(employee.getAddress().equals(deepClone.getAddress()));
  }
}

In the above code snippet, Employee class has reference of Address class which indeed is mutable. We have changed the implementation of clone() and recursively call the clone() of every mutable object reference so that we have new object for those as well.

Some important points to remember

final fields can't be cloned.

Use co-variant return type while overriding the clone().

If you are implementing cloning for thread-safe class, then you need to synchronize the cloning and methods used in cloning.

Alternate to cloning

We can use copy constructor and/or static factory method as an alternate to cloning. The advantage of this approach over cloning is that it doesn't demand unenforcable thinly documented conventions. They don't conflict with proper use of final fields. They don't throw unnecessary checked exceptions. They don't require object casts.

public Employee(Employee employeeToCopy)
public static Employee newInstance(Employee employeeToCopy)

This is how we clone objects in Java. I hope this post is informative and explains pitfall of cloning well. You can find the example code used above on Github.