views:

2827

answers:

4

Java 5 introduced generics, and they were added to many interfaces in the java.lang package. However, Cloneable did not get generics. I wonder why?


Edit: In reply to the answers of @Jon and @litb, and the comment of @Earwicker, I was thinking Cloneable might be:

public interface Cloneable<T> {
    public T clone();
}

Here T clone(); overrides Object.clone(), giving it a covariant type. I believe this would still be backwards compatible and increase type safety. So why not?


Edit 2: As can be seen in the answers (and comments) below, the interface suggested above would break backwards-compatibility. Since Object.clone() is protected, rewriting it in the interface would force all implementers to provide a public implementation, which class designers might not want to (i.e. they might opt to keep it protected).

+12  A: 

The Cloneable interface doesn't contain any members. What would be the point of making it generic?

(If Cloneable contained the clone() method, it would make sense - but that's declared in java.lang.Object.)

EDIT: clone() is in java.lang.Object as it has an implementation (which does a field-by-field copy). A better design would be to have something like .NET's MemberwiseClone() as a protected method in Object, and then a public clone() method within the interface itself. I don't know why that design wasn't chosen.

(In .NET, ICloneable isn't generic because it existed before generics - the different nature of .NET generics prevents a previously non-generic type from becoming generic.)

In both Java and .NET, however, the "normal" cloning API is generally regarded as a bad thing, as it says nothing about what depth of cloning should be performed.

Jon Skeet
Thanks for your reply. I have edited my question to clarify what I was thinking of.
Hosam Aly
The public clone() method in java.lang.Object could not be changed for backward-compatibility. I'm fine with this. But I don't see how the modification I'm suggesting to the interface could be harmful. I think it's backward-compatible, and also type safe. What do you think?
Hosam Aly
Hosam, clone is protected in java.lang.Object . so classes that want to be cloned by outside guys have to override it and make it public explicitly. i think jon talks about the name of clone. c#'s MemberwiseClone makes it clear whats going on.
Johannes Schaub - litb
I agree that MemberwiseClone is a better name. And thanks for reminding me that clone is protected. I am more inclined to think that a class that implements Cloneable would provide a public clone() method, but that's not a necessity. So my interface would indeed break backward-compatibility. Thanks!
Hosam Aly
+6  A: 

java.lang.Cloneable is a marker interface. It's solely for the purpose so that Object.clone can throw an exception to signal a class does not support cloning by using for example

if(!(this instanceof Cloneable))
    throw...;

From the documentation:

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.

It's got no methods. Making it a generic isn't going to be of any use.

Johannes Schaub - litb
Yes, I agree. But wouldn't this marker interface be more useful had it been in the form I wrote in my question edit?
Hosam Aly
i'm sorry i've got no idea. maybe it's backward compatibility (after all generics weren't there since the beginning), or it's for convenience (Object will copy primitives correctly (deeply of course)). I think we'll have to wait for skeet for the explanation for this. im sure he'll know.
Johannes Schaub - litb
+1  A: 

As a semi-related thought question: would creating an interface (call it ReallyCloneable) that exposes clone() as a public member be useful?

My contention is that no, it wouldn't. Clonability is intimately linked to concrete class implementation. I can't think of a single use case where I'm likely to say "I have an arbitrary object, and I want a copy of it." The immediate question would be: why do you want that copy?

And the typical answer is so that you can modify the copy without affecting the original. However, to do that you need to know what type of object you're holding, otherwise how would you know what to call to modify it? And if you know that, you'll know whether or not it provides a public clone() method.

But what if you're programming to an interface, such as List? Intelligent (recursive) cloning (versus byte-level object data copy) would be incredibly useful with the Collections framework. But there may be collections (such as those backed by a database) that can't support such an operation, so you can't require List to expose a public clone(). Which drives you to instantiating your own concrete List implementation to copy the contents of the source List.

kdgregory
+1  A: 

This doesn't address your theoretical question, but handles the practical case:

Java 5 has covariant return values and allows broadening the access of methods. So you're free to change the signature for clone() appropriately in subclasses.

public class MyClass implements Cloneable {
    public MyClass clone(){ /* do the right stuff */ }
}

MyClass.clone() is a correct override of Object.clone(), and you won't have to write casts.