Given a reference to a class which does not implement defensive copying, users of the class can use one of the following techniques:
1) Copy constructor
public class Point { private int x; private int y; Point(Point other) { this.x = other.x; this.y = other.y; } ... }
But this approach has serious drawbacks(Java Design Issues).
Ken Arnold: Suppose you have a Foo, which has a subclass Bar. If you ask Foo to clone itself and you have a Bar object, Foo will do all the Bar stuff. But if you use this copy constructor mechanism and you tell Foo to create a new Foo and pass in the old Bar, you will get a new Foo instead of a Bar. You lose the bottom of the type.
Bill Venners: You’re fubar.
Ken Arnold: You’re definitely fubar. So using a copy constructor implies a mechanism where you ask the passed object its type. You get its class object, and invoke its copy constructor by reflection. When you do that, you are way into ugliness.
Steve Ball has pointed out(Effective Java Effective Cloning) that
The disadvantage of this approach, compared to the clone method, is that it may not be accessed polymorphically and is usually less efficient. Some classes, such as java.util.Date, require even weirder syntax to clone their instances:
Date clone = new Date(birthdate.getTime());
2) Clone
The basic form for clone is as follows:
public Object clone() { try { return (Vec) super.clone(); } catch (CloneNotSupportedException e) { throw new InternalError(e.toString()); } }
Things to remember by Steve (Effective JavaSolutions for implementing dependable clone methods)
– Object.clone may do shallow copy.
– Subclass use the clone of the superclass. If the superclass does not provide correct clone method, all subclasses fail.
– In case of final, consider copy constructor.
– Call super.clone in the parent class, otherwise child class who’s calling super.clone to clone itself will be messed up.
– Consider copy constructor in the nesting class to copy the nested class.
But the clone is broken(Java Design Issues). From Ken,
I would say deprecate Cloneable and have a Copyable, because Cloneable has problems. Besides the fact that it’s misspelled, Cloneable doesn’t contain the clone method. That means you can’t test if something is an instance of Cloneable, cast it to Cloneable, and invoke clone.
From Steve,
Unfortunately, the closer you look at Java’s cloning mechanism, the more clumsy and inelegant it appears—implementers are required to catch and absorb exceptions that cannot possibly be thrown, and have no easy way to disable cloning for classes that inherit a clone method with no checked exceptions. Worse still, if you attempt to define a clone method in the presence of final members or inner classes, Java fights you all the way.
The intrinsic problem is when a reference to Foo is stored as Object, one can not call it’s clone method (Object.clone is protected).
Another problem is that it’s hard to disable clone if the superclass has clone method with no checked exception, because subclasses can not throw CloneNotSupportedException as pointed out by Steve.
Attack of the clones is also worth reading. It discuss various techniques (Object.clone, copy constructor, java serialization, java reflection) for copying an object. Among them, Object.clone and copy constructor are the fastest way to copy an object.
Maybe immutable objects are the answer(Mutable or immutable?, Immutable Objects)?