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.
Object cloning is the process of creating exact copy of the given object. There are two pre-requisite in java:
Cloneable
interface, andjava.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:
x.clone() != x
will be true, and that the expressionx.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.
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
.
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.
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
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.
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.