How to Properly Override Clone Method

How to properly override clone method?

Do you absolutely have to use clone? Most people agree that Java's clone is broken.

Josh Bloch on Design - Copy Constructor versus Cloning

If you've read the item about cloning in my book, especially if you read between the lines, you will know that I think clone is deeply broken. [...] It's a shame that Cloneable is broken, but it happens.

You may read more discussion on the topic in his book Effective Java 2nd Edition, Item 11: Override clone judiciously. He recommends instead to use a copy constructor or copy factory.

He went on to write pages of pages on how, if you feel you must, you should implement clone. But he closed with this:

Is all this complexities really necessary? Rarely. If you extend a class that implements Cloneable, you have little choice but to implement a well-behaved clone method. Otherwise, you are better off providing alternative means of object copying, or simply not providing the capability.

The emphasis was his, not mine.


Since you made it clear that you have little choice but to implement clone, here's what you can do in this case: make sure that MyObject extends java.lang.Object implements java.lang.Cloneable. If that's the case, then you can guarantee that you will NEVER catch a CloneNotSupportedException. Throwing AssertionError as some have suggested seems reasonable, but you can also add a comment that explains why the catch block will never be entered in this particular case.


Alternatively, as others have also suggested, you can perhaps implement clone without calling super.clone.

Overriding Clone() method in Java when superclass is not Clonable

If you have this structure:

class Y {}

class X extends Y implements Cloneable {
@Override
public X clone() {
try {
return (X) super.clone();
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
}

Then clone on instances of X will work fine.
It won't work on direct instances of Y, because they are not declared cloneable. But the Cloneable interface on X is an indicator to the mechanisms of the default clone() implementation that they should be made to work.

Alternatively

You could also have a non-Cloneable class with a working clone() method, as long as you didn't rely on the default implementation of clone().

For instance:

class Y {
@Override
public Y clone() {
// Don't call super.clone() because it will error
return new Y(...); // whatever parameters
}
}

However, with this mechanism, if you called super.clone() from a subclass of Y, you would get an instance of Y, which is probably not what you would want.

As others have pointed out, the Cloneable mechanism is awkward and confusing, and usually copying mechanisms using new are easier to work with.

Why to override clone method in Java

As every class in Java extends from Object, so it should have clone
method but still we are forced to override clone

No you are not forced to override the clone method. In inheritance, when you inherit a class, you are not forced to override it's method. Its modifier being public or protected doesn't make much of a difference. However, if you want to invoke a method directly on super class reference, then that method has to be public. Protected methods are accessible only through inheritance. That is you can only access them through subclass reference. Or if you override the method, you can access them through super keyword.

Having said that, you should not override clone method, as it is broken. Because, for a class to be cloned, you need to implement the Cloneable interface. And then your class uses the clone method of Object class instead. Because, Cloneable interface doesn't exactly have any method for cloning. It would be a better option to use Copy Constructor instead.

public class A {
private int data;
public A() {
}

public A(A a) {
this.data = a.data;
}
}

For more details, I would suggest to go through this chapter of Joshua Bloch's Effective Java, which covers all aspects of using clone method.

Effective Java- Item # 11 - Override clone judiciously

Understanding what happens when we override the clone method with and without invoking super.clone?

You should always use super.clone(). If you don't, and say just return new MyObject(this.x);, then that works fine for instances of MyObject. But if someone extends MyObject, it's no longer possible for them to get an instance of the right class when overriding your clone method. The one thing Object.clone does that you can't do a good job of yourself is creating an instance of the right class; the rest is just copying instance fields, which is drudgework you could have done yourself if you wanted.

Dealing with final fields when overriding clone

Since the call to super.clone(); will already create a (shallow) copy of all the fields, final or not, your full method will become:

@Override
public MyInterface clone() throws CloneNotSupportedException {
return (MyInterface)super.clone();
}

This requires that the superclass also implements clone() properly (to ensure that the super.clone() eventually reaches the Object class. All the fields will be copied properly (including final ones), and if you don't require deep clones or any other special functionality, you can use this and then promise that you'll never try to implement clone() again (one of the reasons being that it's not easy to implement it correctly, as evident from this question).

Java cloning abstract objects

You can try to use reflection:

public abstract class AClonable implements Cloneable{

private String val;

public AClonable(){

}

public AClonable(String s){
val=s;
}

public String toString(){
return val;
}

@Override
public AClonable clone(){
try {
System.out.println(getClass().getCanonicalName());
AClonable b= getClass().getDeclaredConstructor(String.class).newInstance(val);

return b;
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

}

in the clone() method you call getClass(). Because the ACloneble ist abstract, there call will allways go to the concrete class.

   public class ClonebaleOne extends AClonable{

public ClonebaleOne(){
super();
}

public ClonebaleOne(String s) {
super(s);
// TODO Auto-generated constructor stub
}

}

and

  public class ClonebaleTwo extends AClonable{

public ClonebaleTwo(){
super();
}

public ClonebaleTwo(String s) {
super(s);
// TODO Auto-generated constructor stub
}

}

and finally

   public static void main(String[] args){
AClonable one = new ClonebaleOne("One");
AClonable tow= new ClonebaleTwo("Two");
AClonable clone = one.clone();
System.out.println(clone.toString());
clone = tow.clone();
System.out.println(clone.toString());

}

Output:

  ClonebaleOne
One
ClonebaleTwo
Two

But it's more a hack than a solution

[EDIT] my two clones were faster than ;)

[EDIT] To be complete. Another implentation of clone() can be

 @Override
public AClonable clone(){
try {
ByteArrayOutputStream outByte = new ByteArrayOutputStream();
ObjectOutputStream outObj = new ObjectOutputStream(outByte);
ByteArrayInputStream inByte;
ObjectInputStream inObject;
outObj.writeObject(this);
outObj.close();
byte[] buffer = outByte.toByteArray();
inByte = new ByteArrayInputStream(buffer);
inObject = new ObjectInputStream(inByte);
@SuppressWarnings("unchecked")
Object deepcopy = inObject.readObject();
inObject.close();
return (AClonable) deepcopy;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

when your abstract class implements Serialazable. There you write your object to disc and create a copy with the value from the disc.

Why is the clone() method protected in java.lang.Object?

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"



Related Topics



Leave a reply



Submit