Practical Java Praxis 66: Call super.clone when Implementing a clone Method
For classes that support cloning, the clone method of java.lang.Object must be invoked. This is accomplished by an implementation of a clone method invoking super.clone.
A clone method that begins with the super.clone invocation ensures
that the java.lang.Object clone method is eventually called and
that the cloned object is constructed properly. This clone method creates
a new object of the correct type and performs a shallow clone by copying all
fields from the cloned object to the new object. However, even if you require
a deep clone, you still need to invoke the clone method of java.lang.Object
to create the correct type of object. (For a discussion of how a shallow clone
and a deep clone differ, see the
This clone method also ensures that the correct derived object is created. Consider the following code:
class House implements Cloneable { private int numberOfRooms; private int squareFeet; //... public Object clone() { return new House(); } }
For a class to support cloning, it must first implement the Cloneable interface. This interface is a marker interface[md]that is, it does not implement any methods. Classes that implement Cloneable advertise that they support cloning.
The implementation of the clone method in the previous class has a problem. It never calls super.clone. Consider what happens if the House class is subclassed and clone is called on the subclass:
class TwoStoryHouse extends House {} //... TwoStoryHouse tsh = new TwoStoryHouse(); TwoStoryHouse other = (TwoStoryHouse)tsh.clone(); //Exception //...
This code results in a run-time exception. The problem occurs when the clone method of the House class is called from a reference to a TwoStoryHouse. The clone method of House is invoked, and it creates an object of the class House, not of the class TwoStoryHouse. Figure 1 shows the representation of the objects.
Incorrect object layout when super.clone is not called
Therefore, the code attempts to cast an object of class House to a TwoStoryHouse. Because the object was not originally constructed as a TwoStoryHouse, a ClassCastException is thrown by the JVM at runtime.
This problem is fixed by properly implementing the clone method of the House class to call super.clone. Calling super.clone ensures that the clone method of java.lang.Object is called[md]this creates the correct type of object. A properly implemented clone method for the House class looks like this:
class House implements Cloneable { //As before... public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(); } } }
This implementation of the clone method guarantees that the clone method of java.lang.Object method is called. This ensures that the correct object is created so that the code performing the cast does not fail. For example, take a look at this code:
//... TwoStoryHouse tsh = new TwoStoryHouse(); TwoStoryHouse other = (TwoStoryHouse)tsh.clone(); //OK //...
The representations of the objects now look as shown in Figure 2.
Correct object layout after calling super.clone
If you are implementing a deep clone, the same rule applies. You should call
super.clone to acquire the correct type of object and then perform the
deep cloning operations. This technique was implemented on the ShareVector
class in the
About the Author
Peter Haggar is a senior software engineer with IBM in Research Triangle Park, North Carolina, and author of the best-selling book Practical Java, published by Addison-Wesley. Having worked on development tools, class libraries, and operating systems, he has a broad range of programming experience. At IBM, Peter works on emerging Java technology and, most recently, on real-time Java. He is also a frequent technical speaker on Java technology at numerous industry conferences. Peter received his bachelor of science degree in computer science from Clarkson University. He can be contacted at haggar@us.ibm.com.