Cloning is a basic programming paradigm. The fact that Java may have implemented it weakly in many ways does not at all reduce the need for cloning. And, it's easy to implement cloning that will work, but you want it to work, shallow, deep, mixed, whatever. You can even use name cloning for a function and not use Cloneable if you want.
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 this list can contain objects of type A, B or C. You do not know what type of objects. Therefore, you cannot copy the list as follows:
ArrayList<A> list2 = new ArrayList<A>(); for(A a : list1) { list2.add(new A(a)); }
If the object does indeed have type B or C, you will not get the correct 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 do not have access to them in this class?
What you would like to do is:
ArrayList<A> list2 = new ArrayList<A>(); for(A a : list1) { list2.add(a.clone()); }
Many people have indicated why the underlying implementation of the Java clone is problematic. But he easily overcomes this path:
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 do not implement Cloneable, just using the same function name. If you do not like it, call it something else.