The Cloneable interface specifies that an object can be cloned. Often it is desirable to create a copy of an object. To do this, you need to use the clone method and understand the Cloneable interface.
An interface contains constants and abstract methods, but the Cloneable interface is a special case. The Cloneable interface in the java.lang package is defined as follows:
package java.lang;
public interface Cloneable {
}
This interface is empty. An interface with an empty body is referred to as a marker interface. A marker interface does not contain constants or methods. It is used to denote that a class possesses certain desirable properties. A class that implements the Cloneable interface is marked cloneable, and its objects can be cloned using the clone() method defined in the Object class.
Many classes in the Java library (e.g., Date, Calendar, and ArrayList) implement Cloneable. Thus, the instances of these classes can be cloned. For example, the following code
1 Calendar calendar = new GregorianCalendar(2013, 2, 1);
2 Calendar calendar1 = calendar;
3 Calendar calendar2 = (Calendar)calendar.clone();
4 System.out.println("calendar == calendar1 is " +
5 (calendar == calendar1));
6 System.out.println("calendar == calendar2 is " +
7 (calendar == calendar2));
8 System.out.println("calendar.equals(calendar2) is " +
9 calendar.equals(calendar2));
displays
calendar == calendar1 is true
calendar == calendar2 is false
calendar.equals(calendar2) is true
In the preceding code, line 2 copies the reference of calendar to calendar1, so calendar and calendar1 point to the same Calendar object. Line 3 creates a new object that is the clone of calendar and assigns the new object’s reference to calendar2. calendar2 and calendar are different objects with the same contents.
The following code
1 ArrayList<Double> list1 = new ArrayList<>();
2 list1.add(1.5);
3 list1.add(2.5);
4 list1.add(3.5);
5 ArrayList<Double> list2 = (ArrayList<Double>)list1.clone();
6 ArrayList<Double> list3 = list1;
7 list2.add(4.5);
8 list3.remove(1.5);
9 System.out.println("list1 is " + list1);
10 System.out.println("list2 is " + list2);
11 System.out.println("list3 is " + list3);
displays
list1 is [2.5, 3.5]
list2 is [1.5, 2.5, 3.5, 4.5]
list3 is [2.5, 3.5]
In the preceding code, line 5 creates a new object that is the clone of list1 and assigns the new object’s reference to list2. list2 and list1 are different objects with the same contents. Line 6 copies the reference of list1 to list3, so list1 and list3 point to the same ArrayList object. Line 7 adds 4.5 into list2. Line 8 removes 1.5 from list3. Since list1 and list3 point to the same ArrayList, line 9 and 11 display the same content.
You can clone an array using the clone method. For example, the following code
1 int[] list1 = {1, 2};
2 int[] list2 = list1.clone();
3 list1[0] = 7;
4 list2[1] = 8;
5 System.out.println("list1 is " + list1[0] + ", " + list1[1]);
6 System.out.println("list2 is " + list2[0] + ", " + list2[1]);
displays
list1 is 7, 2
list2 is 1, 8
To define a custom class that implements the Cloneable interface, the class must override the clone() method in the Object class. The program below defines a class named House that implements Cloneable and Comparable.
package demo;
public class House implements Cloneable, Comparable<House> {
private int id;
private double area;
private java.util.Date whenBuilt;
public House(int id, double area) {
this.id = id;
this.area = area;
whenBuilt = new java.util.Date();
}
public int getId() {
return id;
}
public double getArea() {
return area;
}
public java.util.Date getWhenBuilt(){
return whenBuilt;
}
@Override /** Override the protected clone method defined in the object class, and strengthen its accessibility */
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
@Override // Implement the compareTo method defined in Comparable
public int compareTo(House o) {
if(area > o.area)
return 1;
else if(area < o.area)
return -1;
else
return 0;
}
}
The House class implements the clone method (lines 26–28) defined in the Object class.
The header is:
protected native Object clone() throws CloneNotSupportedException;
The keyword native indicates that this method is not written in Java but is implemented in the JVM for the native platform. The keyword protected restricts the method to be accessed in the same package or in a subclass. For this reason, the House class must override the method and change the visibility modifier to public so that the method can be used in any package. Since the clone method implemented for the native platform in the Object class performs the task of cloning objects, the clone method in the House class simply invokes super.clone(). The clone method defined in the Object class may throw CloneNotSupportedException.
The House class implements the compareTo method (lines 32–39) defined in the Comparable interface. The method compares the areas of two houses.
You can now create an object of the House class and create an identical copy from it, as follows:
House house1 = new House(1, 1750.50);
House house2 = (House)house1.clone();
house1 and house2 are two different objects with identical contents. The clone method in the Object class copies each field from the original object to the target object. If the field is of a primitive type, its value is copied. For example, the value of area (double type) is copied from house1 to house2. If the field is of an object, the reference of the field is copied. For example, the field whenBuilt is of the Date class, so its reference is copied into house2, as shown in Figure below. Therefore, house1.whenBuilt == house2.whenBuilt is true, although house1 == house2 is false. This is referred to as a shallow copy rather than a deep copy, meaning that if the field is of an object type, the object’s reference is copied rather than its contents.
(a) The default clone method performs a shallow copy. (b) The custom clone method performs a deep copy.
To perform a deep copy for a House object, replace the clone() method in lines 27–29 with the following code:
public Object clone() throws CloneNotSupportedException {
// Perform a shallow copy
House houseClone = (House)super.clone();
// Deep copy on whenBuilt
houseClone.whenBuilt = (java.util.Date)(whenBuilt.clone());
return houseClone;
}
or
public Object clone() {
try {
// Perform a shallow copy
House houseClone = (House)super.clone();
// Deep copy on whenBuilt
houseClone.whenBuilt = (java.util.Date)(whenBuilt.clone());
return houseClone;
}
catch (CloneNotSupportedException ex) {
return null;
}
}
Now if you clone a House object in the following code:
House house1 = new House(1, 1750.50);
House house2 = (House)house1.clone();
house1.whenBuilt == house2.whenBuilt will be false. house1 and house2 contain two different Date objects, as shown in Figure (b) below.