Object
does have a protected clone
method and the Cloneable
interface does not have any methods. Then I started wondering how adding an interface with no methods could stop a super class protected method from throwing. So I tried it:public class AnObject
{
public AnObject clone()
{
AnObject obj = null;
try
{
obj = (AnObject)super.clone();
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
return obj;
}
public static void main(String[] args)
{
new AnObject().clone();
}
}
Sure enough, it threw CloneNotSupportedException
. So I added the Cloneable
interface:public class AnObject implements Cloneable
{
...
public static void main(String[] args)
{
new AnObject().clone();
}
}
and the exception went away. I was puzzled until I remembered Java's reflection mechanism. Object
's protected clone
method, when called, must check to make sure that subclasses implement the Cloneable
interface and throw the exception if they don't. Mystery over. However, it's a shame that the item didn't explain that explicitly.The item does point out that although
Object
's clone method returns an Object
, since Java 1.5 covariant return types allow an overriding method to return a different type to the method it is overriding. Based on this I wonder if the Cloneable
interface ought to look more like this:public interface Cloneable
{
T clone();
}
The the subclass would look like this:public class AnObject implements Cloneable
{
@Override
public AnObject clone()
{
AnObject obj = null;
try
{
obj = (AnObject)super.clone();
}
catch (CloneNotSupportedException e)
{
e.printStackTrace();
}
return obj;
}
}
This of course wont work with the current implementation as Object's clone method still looks for the original Cloneable interface.The things to remember are:
- If you override the
clone
method in a nonfinal class, you should return the object obtained by invokingsuper.clone
. - In practice, a class that implements
Cloneable
is expected to provide a properly functioningclone
method
The item then goes on to discuss the need for implementing deep copying when writing a
clone
method for a class that refers to other objects. Cloning the Stack
example shown in the item, without performing a deep copy, results in two Stack
objects both referring to the same elements. This can be overcome by making the clone
method clone the elements as well as the Stack
object.Finally the item explains that it is better to provide an alternative means of object copying, or simply not providing the capability. The alternatives it recommends are a copy constructor:
public AnObject(AnObject obj);
or a copy factory:
public static AnObject newInstance(AnObject obj);
I think the item presents a reasonable case for generally avoiding the
Cloneable
interface.Paul Grenyer
No comments:
Post a Comment