9

The Java specification for the java.lang.Cloneable interface defines itself as signifying that any object that extends it also has implemented the clone() method that rests dormant within java.lang.Object. Specifically, it says that:

A class implements the Cloneable interface to indicate to the java.lang.Object#clone() method that it is legal for that method to make a field-for-field copy of instances of that class.

To me, this means that it should be assumed that every class that extends Cloneable therefore also has a public Object clone() method within it. This makes it easy to assume that the following is a valid method:

public static makeACloneFrom(Cloneable c)
{
  return c.clone();
}

however, this is not the case, as the entirety of the Cloneable source code (sans javadoc) is simply

package java.lang;

public interface Cloneable {
}

Which means that Cloneable#clone() does not exist (and trying to compile the example method above throws a compile-time error saying something like "cannot find symbol: method clone()"). Shouldn't the source code of Cloneable contain something to the effect of public Cloneable clone();?

Why aren't we allowed to assume that a class that implements Cloneable has a public Cloneable clone() method?

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Ky -
  • 30,724
  • 51
  • 192
  • 308
  • possible duplicate of [Java: Rationale of the Cloneable interface](http://stackoverflow.com/questions/709380/java-rationale-of-the-cloneable-interface) – Matt Ball Apr 02 '12 at 18:38

2 Answers2

7

Because it's a poorly-designed interface.

From Effective Java (sorry, Google Books does not have a preview for the 2nd edition):

Item 11: Override clone judiciously

The Cloneable interface was intended as a mixin interface (Item 18) for objects to advertise that they permit cloning. Unfortunately, it fails to serve this purpose. Its primary flaw is that it lacks a clone method, and Object's clone method is protected. You cannot, with resorting to reflection (Item 53), invoke the clone method on an object merely because it implements Cloneable. Even a reflective invocation may fail, as there is no guarantee that the object has an accessible clone method.

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • ... so, pretty much, this is something that should be changed in Java 1.8? – Ky - Apr 02 '12 at 18:40
  • 2
    It should have been changed _long_ ago. I don't think it will ever be, however, because it would introduce backward-incompatibilities. If there is a "fix" in Java 1.8, I imagine it will be something along the lines of a `@Copyable` annotation. – Matt Ball Apr 02 '12 at 18:42
  • I'm not convinced that any "copyable" annotation or interface would work, just because the EJ-approved way to do copying and the like is with a static factory (EJ item 1), which isn't really doable with an interface, and there wouldn't really be any added value from an annotation? – Louis Wasserman Apr 02 '12 at 18:47
  • This `Clonable` interface is one of the biggest junk the Java language has to offer. Why doesn't Oracle remove it or drastically change it ? There are very few people and projects who use it. But uses for it can be found, and pretty often. So Oracle, if you see this, CHANGE IT !!!!!! – Radu Murzea Apr 02 '12 at 18:48
  • 2
    @SoboLAN How would you like it changed? Removing it would cause lots of compatibility issues for little gain. Adding to something badly designed and you shouldn't use, really? – Tom Hawtin - tackline Apr 02 '12 at 18:53
  • 1
    ::sigh:: As much as I hate `Cloneable` and `clone`, I'd rather see them deprecated than deleted outright. – Louis Wasserman Apr 02 '12 at 18:55
  • I meant it should be deprecated or completely refactored... didn't use the right words... The losses are minimal (because it's currently extremely avoided) and the gains are quite significant (because there are plenty of use cases out there...) – Radu Murzea Apr 02 '12 at 19:10
  • 1
    Nevertheless, Oracle can't exactly refactor the code of all Java users out there, and its policy is to basically avoid breaking outside code at all costs. – Louis Wasserman Apr 02 '12 at 19:36
  • If you implement `Cloneable` and don't specify a `clone()` method, it's your fault if your program breaks from being forward-incompatible. – Ky - Apr 02 '12 at 20:21
7

Ugh. clone and Cloneable are broken, terribly designed, and shouldn't be used in new code. (See Effective Java item 11.)

The reason for this particular thing is that Cloneable is a confusingly implemented, magical interface such that the mere act of implementing Cloneable changes the behavior of Object.clone with reflection. Effective Java says:

...if a class implements Cloneable, Object’s clone method returns a field-by-field copy of the object; otherwise it throws CloneNotSupportedException. This is a highly atypical use of interfaces and not one to be emulated...

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • I don't think reflection has anything to do with it (it pre-dates reflection for one thing). – Tom Hawtin - tackline Apr 02 '12 at 18:54
  • Oh man, that's _even more evil._ I guess the native implementation of `clone` does something equivalent to reflection internally? – Louis Wasserman Apr 02 '12 at 18:54
  • According to the 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 and that the return type of the clone method of an array type T[] is T[] where T is any reference or primitive type. 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, ... – Ky - Apr 02 '12 at 20:16
  • ... as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation." – Ky - Apr 02 '12 at 20:16
  • Yeah, but it must do that `Cloneable` check natively rather than in Java. – Louis Wasserman Apr 02 '12 at 20:40