How does Cloneable work in Java and how do I use it?
I would like to know the following:
-
Cloneable
means we can have a clone or a copy of objects, by implementing theCloneable
interface. What are the advantages and disadvantages of doing that? - How does the recursive cloning happen if the object is a composite object?
Solution 1:
The first thing you should know about Cloneable
is - don't use it.
It is very hard to implement cloning with Cloneable
right, and the effort is not worth it.
Instead of that use some other options, like apache-commons SerializationUtils
(deep-clone) or BeanUtils
(shallow-clone), or simply use a copy-constructor.
See here for the views of Josh Bloch about cloning with Cloneable
, which explains the many drawbacks of the approach. (Joshua Bloch was a Sun employee, and led the development of numerous Java features.)
Solution 2:
Cloneable itself is unfortunately just a marker-interface, that is: it does not define the clone() method.
What is does, is change the behavior of the protected Object.clone() method, which will throw a CloneNotSupportedException for classes that do not implement Cloneable, and perform a member-wise shallow copy for classes that do.
Even if this is the behavior you are looking for, you'll still need to implement your own clone() method in order to make it public.
When implementing your own clone(), the idea is to start with the object create by super.clone(), which is guaranteed to be of the correct class, and then do any additional population of fields in case a shallow copy is not what you want. Calling a constructor from clone() would be problematic as this would break inheritance in case a subclass wants to add its own additional cloneable logic; if it were to call super.clone() it would get an object of the wrong class in this case.
This approach bypasses any logic that may be defined in your constructors though, which could potentially be problematic.
Another problem is that any subclasses that forget to override clone() will automatically inherit the default shallow copy, which is likely not what you want in case of mutable state (which will now be shared between the source and the copy).
Most developers don't use Cloneable for these reasons, and simply implement a copy constructor instead.
For more information and potential pitfalls of Cloneable, I highly recommend the book Effective Java by Joshua Bloch
Solution 3:
- Cloning invokes an extra-linguistic way of constructing objects - without constructors.
- Cloning requires you to treat somehow with CloneNotSupportedException - or to bother client code for treating it.
- Benefits are small - you just don't have to manually write a copying constructor.
So, use Cloneable judiciously. It doesn't give you sufficient benefits in comparison with the effort you need to apply to do everything right.
Solution 4:
Cloning is a basic programming paradigm. The fact that Java may have implemented it poorly in many ways does not at all diminish the need for cloning. And, it is easy to implement cloning that will work however you want it to work, shallow, deep, mixed, whatever. You can even use the name clone for the function and not implement Cloneable if you like.
Suppose I have classes A, B, and C, where B and C are derived from A. If I have a list of objects of type A like this:
ArrayList<A> list1;
Now, that list can contains objects of type A, B, or C. You don't know what type the objects are. So, you can't copy the list like this:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(new A(a));
}
If the object is actually of type B or C, you will not get the right copy. And, what if A is abstract? Now, some people have suggested this:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
if(a instanceof A) {
list2.add(new A(a));
} else if(a instanceof B) {
list2.add(new B(a));
} else if(a instanceof C) {
list2.add(new C(a));
}
}
This is a very, very bad idea. What if you add a new derived type? What if B or C are in another package and you don't have access to them in this class?
What you would like to do is this:
ArrayList<A> list2 = new ArrayList<A>();
for(A a : list1) {
list2.add(a.clone());
}
Lots of people have indicated why the basic Java implementation of clone is problematic. But, it's easily overcome this way:
In class A:
public A clone() {
return new A(this);
}
In class B:
@Override
public B clone() {
return new B(this);
}
In class C:
@Override
public C clone() {
return new C(this):
}
I'm not implementing Cloneable, just using the same function name. If you don't like that, name it something else.