1

I am studying Java because I need it as a prerequirement in one of my college courses. I come from a C++ background, so understanding the logic underlying OOP is not particularly difficult. But there are several differences between the two languages, and one I just cannot figure out is the object cloning feature present in Java. The problem recalls me that of the copy constructor for C++, but the implications are just different.

In Java, there are no destructors and memory is managed by a garbage collector, so there are not the heap memory issues you face in C++. The problem is limited to sharing variables.

Now, reading around, I found that object cloning (unlike copy constructors) is not a feature that an OOP language should provide, as it creates another instance of an object skipping the construction phase. Moreover, clone() cannot manipulate final fields properly, and skip initialization blocks. The same logic behind clonation is "wrong" because "Cloneable" is just like an empty interface, provided only to make a type check in Object.clone(), to raise an exception if the type of the object is not Cloneable.

All the cloning mechanism seems to rely on the Object.clone() method, which allocates memory properly. Each subtype in the class hierarchy supporting clone(), should make a call to "super.clone()" until the Object one is called to allocate all necessary fields. But what happens if a subtype, implementing the Cloneable interface, extends a supertype not doing so? I'm studying from "Arnold, Gosling, Holmes", and one of the defined behaviours towards clone is: "Allow subclasses to support clone but don't publicly support it. Such a class doesn't implement Cloneable, but if the default implementation of clone isn't correct, the class provides a protected clone implementation that clones its fields correctly". This way, calling super.clone(), in the end we will bump into the protected clone() method of the superclass, but such method cannot rely on Object.clone(), because the superclass itself doesn't implement Cloneable. Using the new operator would be an error, because an instance of the superclass would be created, with some missing fields.

So, is supporting clone() (with a protected method) in a non-Cloneable class really useful? And how can one solve the problem of a Cloneable subtype with non-Cloneable supertype?

D. Samp
  • 11
  • 2
  • 2
    Cloneable / clone() is a completely broken mechanism. I'd suggest you avoid it. Read Effective Java Item 11: Override clone judiciously . Or read this: http://www.artima.com/intv/bloch13.html – Sean Patrick Floyd Sep 17 '15 at 13:26
  • Some OOP courses will teach you how to properly implement a clone (using copy constructors), and will require you to do so in your data classes. However, in practice, supporting clone is either not too useful or not a wise choice. You can do it, but you should think beforehand if it is worth it. – afsantos Sep 17 '15 at 13:28
  • Also, possibly related: http://stackoverflow.com/questions/2326758/how-to-properly-override-clone-method – afsantos Sep 17 '15 at 13:29

2 Answers2

2

But what happens if a subtype, implementing the Cloneable interface, extends a supertype not doing so?

If it just implements Cloneable without actually overriding clone() (yes, that's also possible!), then no harm is done.

If it overrides clone() and returns an instance which was not retrieved from super.clone(), then it has broken all its subclasses. This is one of the acknowledged pitfalls of clone() (covered in Effective Java).

how can one solve the problem of a Cloneable subtype with non-Cloneable supertype?

As explained above, this is not an issue as long as the non-cloneable supertype does not override clone() (and yes, that's yet another possibility!) or does override it, but in a compliant manner.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • So, even if the supertype does not implement Cloneable, if the clone() method of the subtype calls super.clone(), the Object.clone() is actually called. But you cannot but get a shallow copy of the superclass fields – D. Samp Sep 17 '15 at 16:49
  • Surely you meant "deep copy". No, you can't get that, but at least that's not a specific issue with Cloneable. – Marko Topolnik Sep 17 '15 at 17:18
0

how can one solve the problem of a Cloneable subtype with non-Cloneable super type?

Actually this is not a problem. Think of class Object: this is a non-Cloneable type, and used as super type of any Cloneable type. You can create a Cloneable subtype of any type T. The only thing that matters: is the 'clone' operation implemented correctly for that type T (and its super types). For the class Object this is will return a field-wise, shallow copy of the original object, with the same class as the original object.

I.e. not every type in the super class thread of a sub class must implement Cloneable.

... is supporting clone() (with a protected method) in a non-Cloneable class really useful?

Yes. E.g. see the default implementation of clone() in the (non-Cloneable) class Object.

Udo Borkowski
  • 311
  • 1
  • 9
  • I get what you mean. But this puzzles me: if the supertype doesn't implement Cloneable but provides a protected clone() method, if the subtype calls super.clone(), the protected method of the superclass will be called instead. So, the copy is going to be broken, as the supertype cannot call Object.clone() – D. Samp Sep 17 '15 at 17:01
  • I ran some tests. If your supertype does not implement Cloneable, but you provide a protected clone() method that uses super.clone(), it can access Object.clone(), as long as the subtype calling super.clone() (inside its overridden clone() method) implements Cloneable. In fact, the type check executed by Object.clone(), is performed on this, which points to a Cloneable object of the subtype – D. Samp Sep 17 '15 at 18:07