Object Cloning in Java

We will start with what What object cloning is and then will implement it with an example and then we will discuss deep cloning and shallow cloning and end the post with alternative to cloning.

1. What is Object Cloning in Java?

Object cloning is the process of creating exact copy of the given object. There are two pre-requisite in java:

  1. implement Cloneable interface, and
  2. override the clone() method defined in the 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.

Points to remember

  • 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:

2. What is Cloneable interface and is 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.

3. 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.

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("Street XYZ", "Smart City", "India"));
Employee shallowClone = employee.clone();
employee.getAddress().setCity("Home City");
// should return false but returning true
System.out.println(employee.getAddress().equals(shallowClone.getAddress()));
}
}

In the above code snippet, Employee class's clone() method called the super.clone() i.e. Object class's clone() method. The only problem in case of shallow cloning is when you have composed of Objects in your class.

In the above example, Employee class has Address class composed of. If you change anything in shallow cloned object reference, it will be reflected in original object reference as well.

When to use shallow cloning

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

4. Deep Cloning

The process of recursively clone each and every instance field of the object. Let's update Employee class from previous example to deep clone the object.

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.

Points to remember

5. Alternative 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.

// Copy constructor
public Employee(Employee employeeToCopy)

// Static factory method
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.



Tags: Object cloning in Java, Deep Cloning, Shallow Cloning, Shallow Cloning v/s Deep Cloning, Java

← Back home