I did a quick google on implementing clone() in Java and found: http://www.javapractices.com/topic/TopicAction.do?Id=71
It has the following comment:
copy constructors and static factory methods provide an alternative to clone, and are much easier to implement.
All I want to do is make a deep copy. Implementing clone() seems to make a lot of sense, but this highly google ranked article makes me a bit afraid.
Here are the issues that I've noticed:
Copy constructors don't work with Generics.
Here's some pseudo-code that won't compile.
public class MyClass<T>{
..
public void copyData(T data){
T copy=new T(data);//This isn't going to work.
}
..
}
Sample 1: Using a copy constructor in a generic class.
Factory methods don't have standard names.
It's quite nice to have an interface for reusable code.
public class MyClass<T>{
..
public void copyData(T data){
T copy=data.clone();//Throws an exception if the input was not cloneable
}
..
}
Sample 2: Using clone() in a generic class.
I noticed that clone is not a static method, but wouldn't it still be necessary to make deep copies of all the protected fields? When implementing clone(), the extra effort to throw exceptions in non-cloneable subclasses seems trivial to me.
Am I missing something? Any insights would be appreciated.
What you are missing is that clone creates shallow copies by default and convention, and that making it create deep copies is, in general, not feasible.
The problem is that you cannot really create deep copies of cyclic object graphs, without being able to keep track what objects have been visited. clone() does not provide such tracking (as that would have to be a parameter to .clone()), and thus only creates shallow copies.
Even if your own object invokes .clone for all of its members, it still won't be a deep copy.
Basically, clone is broken. Nothing will work with generics easily. If you have something like this (shortened to get the point across):
Then with a compiler warning you can get the job done. Because generics are erased at runtime, something that does a copy is going to have a compiler warning generating cast in it.
It is not avoidable in this case.. It is avoidable in some cases (thanks, kb304) but not in all. Consider the case where you have to support a subclass or an unknown class implementing the interface (such as you were iterating through a collection of copyables that didn't necessarily generate the same class).Below are some cons due to which many developers don't use
Object.clone()
Object.clone()
method requires us to add lots of syntax to our code like implementCloneable
interface, defineclone()
method and handleCloneNotSupportedException
and finally call toObject.clone()
and cast it our object.Cloneable
interface lacksclone()
method, it is a marker interface and doesn’t have any method in it, and still we need to implement it just to tell JVM that we can performclone()
on our object.Object.clone()
is protected so we have to provide our ownclone()
and indirectly callObject.clone()
from it.Object.clone()
doesn’t invoke any constructor.clone()
method in a child class e.g.Person
then all of its superclasses should defineclone()
method in them or inherit it from another parent class otherwisesuper.clone()
chain will fail.Object.clone()
support only shallow copy, so reference fields of our newly cloned object will still hold objects which fields of our original object was holding. In order to overcome this, we need to implementclone()
in every class who’s reference our class is holding and then clone them separately in ourclone()
method like in below example.Object.clone()
because final fields can only be changed through constructors. In our case, if we want everyPerson
object to be unique by id, we will get the duplicate object if we useObject.clone()
becauseObject.clone()
will not call the constructor and finalid
field can’t be modified fromPerson.clone()
.Copy constructors are better than
Object.clone()
because theyRead more on Java Cloning - Copy Constructor versus Cloning
One pattern that may work for you is bean-level copying. Basically you use a no-arg constructor and call various setters to provide the data. You can even use the various bean property libraries to set the properties relatively easily. This isn't the same as doing a clone() but for many practical purposes it's fine.
I think Yishai answer could be improved so we can have no warning with the following code:
This way a class that need to implements Copyable interface has to be like this:
Usually, clone() works in tandem with a protected copy constructor. This is done because clone(), unlike a constructor, can be virtual.
In a class body for Derived from a super class Base we have
So, at its most simplistic, you would add to this a virtual copy constructor with the clone(). (In C++, Joshi recommends clone as the virtual copy constructor.)
It gets more complicated if you want to call super.clone() as is recommended and you have to add these members to the class, you can try this
Now, if an execution, you got
and you then did
this would invoke, clone() in the Derived class (the one above), this would invoke super.clone() - which may or may not be implemented, but you're advised to call it. The implementation then passes output of super.clone() to a protected copy constructor that takes a Base and you pass any final members to it.
That copy constructor then invokes the copy constructor of the super-class (if you know that it has one), and sets the finals.
When you come back to the clone() method, you set any non-final members.
Astute readers will notice that if you have a copy-constructor in the Base, it will be called by super.clone() - and will be called again when you invoke the super-constructor in the protected constructor, so you may be calling the super copy-constructor twice. Hopefully, if it is locking resources, it will know that.