What is the specific reason that clone()
is defined as protected in java.lang.Object
?
views:
2135answers:
8clone
is protected because it is something that ought to be overridden so that it is specific to the current class. While it would be possible to create a public clone
method that would clone any object at all this would not be as good as a method written specifically for the class that needs it.
The fact that clone is protected is extremely dubious - as is the fact that the clone
method is not declared in the Cloneable
interface.
It makes the method pretty useless for taking copies of data because you cannot say:
if(a instanceof Cloneable) {
copy = ((Cloneable) a).clone();
}
I think that the design of Cloneable
is now largely regarded as a mistake (citation below). I would normally want to be able to make implementations of an interface Cloneable
but not necessarily make the interface Cloneable
(similar to the use of Serializable
). This cannot be done without reflection:
ISomething i = ...
if (i instanceof Cloneable) {
//DAMN! I Need to know about ISomethingImpl! Unless...
copy = (ISomething) i.getClass().getMethod("clone").invoke(i);
}
Citation From Josh Bloch's Effective Java:
"The Cloneable interface was intended as a mixin interface for objects to advertise that they permit cloning. Unfortunately it fails to serve this purpose ... This is a highly atypical use of interfaces and not one to be emulated ... In order for implementing the interface to have any effect on a class, it and all of its superclasses must obey a fairly complex, unenforceable and largely undocumented protocol"
The Clone method can't be directly used on any object, which is why it is intended to be overriden by the subclass.
Of course it could be public and just throw an appropriate exception when cloning is not possible, but i think that would be misleading.
The way clone is implemented right now makes you think about why you want to use clone, and how you want your object to be cloned.
It is protected because the default implementation does a shallow memberwise copy of all fields (including private), circumventing constructor. This is not something an object might be designed to handle in the first place (for example, it might keep track of created object instances in a shared list, or something similar).
For the same reason, the default implementation of clone()
will throw if the object it's called on doesn't implement Cloneable
. It's a potentially unsafe operation with far-reaching consequences, and therefore author of the class must explicitly opt-in.
From the javadoc of cloneable.
* By convention, classes that implement this interface (cloneable) should override
* <tt>Object.clone</tt> (which is protected) with a public method.
* See {@link java.lang.Object#clone()} for details on overriding this
* method.
* Note that this interface does <i>not</i> contain the <tt>clone</tt> method.
* Therefore, it is not possible to clone an object merely by virtue of the
* fact that it implements this interface. Even if the clone method is invoked
* reflectively, there is no guarantee that it will succeed.
So you could call clone on every object but this would give you most of the time not the results you want or an exception. But is only encouraged if you implement cloneable.
The Clonable interface is just a marker saying the class can support clone. The method is protected because you shouldn't call it on object, you can (and should) override it as public.
From Sun:
In class Object, the clone() method is declared protected. If all you do is implement Cloneable, only subclasses and members of the same package will be able to invoke clone() on the object. To enable any class in any package to access the clone() method, you'll have to override it and declare it public, as is done below. (When you override a method, you can make it less private, but not more private. Here, the protected clone() method in Object is being overridden as a public method.)
Yes, same problem that I met. But I solve it by implementing this code
public class Side implements Cloneable {
public Side clone() {
Side side = null;
try {
side = (Side) super.clone();
} catch (CloneNotSupportedException e) {
System.err.println(e);
}
return side;
}
}
Just as the before someone said.
Again, Java JDK framework shows brilliant thinking:
Cloneable interface does not contain a "public T clone();" method because it acts more like an attribute (eg. Serializable) which allows an instance it to be cloned.
There is nothing wrong with this design because:
Object.clone() will not do what you want with your custom-defined class.
If you have Myclass implements Cloneable => you overwrite clone() with "public MyClass clone()"
If you have MyInterface extends Cloneable and some MyClasses implementing MyInterface: simply define "public MyInterface clone();" in the interface and every method using MyInterface objects will be able to clone them, no matter their MyClass-class.
Victor, cs.ubbcluj.ro