tags:

views:

2135

answers:

8

What is the specific reason that clone() is defined as protected in java.lang.Object?

+3  A: 

clone 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.

Andrew Hare
but why has it to be protected for that?
Janusz
It's protected so you don't use the one in object (it'll just throw an exception anyway). They want you to override it in a class, then you make it public. (answered a couple times below too)
Bill K
And useless when considering interfaces as per my point below
oxbow_lakes
+15  A: 

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"

oxbow_lakes
If the object isn't Cloneable, then Object's clone() will throw CloneNotSupportedException. So you do need be Cloneable if you're going to call super.clone() (resulting in Object.clone() being called). I don't see how an object can be serialized without implementing Serializable.
Steve Kuo
"I think that the design of Cloneable is now largely regarded as a mistake." [citation needed]
Kevin Panko
Sorry - I wasn't implying that. I was merely implying that "good" design is to *not* make an interface extend `Serializable` - it is up to implementations to decide whether to implement `Serializable`. I was extending this to `Cloneable` - it is not something which an interface should extend - but an implementation of an interface is free to be `Cloneable`. The trouble is, if you have a parameter of the interface type, you ask ask it whether it is cloneable; but then you can't actually clone it!
oxbow_lakes
@Kevin - **Josh Bloch's** effective Java pp45. *"The Cloneable interface was intended as a mixin interface for objects to advertise that they permit cloning. Unfortunately it fails to serve this purpose"*
oxbow_lakes
Also on the same page: *"This is a highly atypical use of interfaces and not one to be emulated"* and *"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**"*
oxbow_lakes
Josh is hardly being effusive is he?
oxbow_lakes
Citation added to main entry
oxbow_lakes
+1, good answer.
Michael Myers
+1  A: 

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.

Silfverstrom
+1  A: 

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.

Pavel Minaev
Actually the default implementation (in object) throws an exception according to the docs...
Bill K
No, it doesn't just throw. From its JavaDoc: "The method clone for class Object performs a specific cloning operation. First, if the class of this object does not implement the interface Cloneable, then a CloneNotSupportedException is thrown. Note that all arrays are considered to implement the interface Cloneable. Otherwise, this method creates a new instance of the class of this object and initializes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned."
Pavel Minaev
+1  A: 

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.

Janusz
You _cannot_ call clone on every Object, because it's protected!
Pavel Minaev
Sorry for my a little bit unclear last two sentences...
Janusz
+2  A: 

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.)

Bill K
Which is fine, *until you bring interfaces into the mix* - try and attempt to clone an unknown implementation of `Set`
oxbow_lakes
@oxbow_lakes: but maybe some implementations of Set are not cloneable
newacct
You can't clone anything that doesn't implement the Clonable interface--it's a marker that says "This class is properly clonable"--very similar to the Serializable interface. By the way, there is a way to clone classes via serialization that works well--google something like "java serialization clone" and you'll probably find a handful of ways to get a deep copy of your object.
Bill K
You can't clone anything that doesn't implement the Cloneable interface, but just because something implements the Cloneable interface doesn't mean you can clone it.
Michael Myers
@mmyers Your comment is correct, but if that was in reply to the comment above it then you missed what I was saying. A class that can't be cloned but can be serialized can be "cloned" (or let's just say copied) via serialization. This makes an excellent, cheap (to code) cloning system, just serialize it out to a byte array and serialize it back into another variable.
Bill K
A: 

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.

CloneNotSupportedException is another example of a checked exception that should be unchecked (that is, it should extend RuntimeException, not Exception). Though method clone() in class Side implements Cloneable and therefore will never throw CloneNotSupportedException, Side.clone() must still catch or declare the exception. This just adds superfluous exception handling noise to the clone() method.
Derek Mahar
A: 

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:

  1. Object.clone() will not do what you want with your custom-defined class.

  2. If you have Myclass implements Cloneable => you overwrite clone() with "public MyClass clone()"

  3. 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

Victor