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 thatCloneable
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-behavedclone
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
How to Directly Initialize a Hashmap (In a Literal Way)
How to Implement Constants in Java
Reading a List from Properties File and Load with Spring Annotation @Value
Scanner VS. Stringtokenizer VS. String.Split
How to Ensure Order of Processing in Java8 Streams
How to Monitor the Computer's Cpu, Memory, and Disk Usage in Java
Preferred Way of Loading Resources in Java
Spring Data JPA - Zoneddatetime Format for JSON Serialization
Slf4J: Failed to Load Class "Org.Slf4J.Impl.Staticloggerbinder"
How to Map a Composite Key with JPA and Hibernate
What Is the "Continue" Keyword and How Does It Work in Java
How Does a Arraylist's Contains() Method Evaluate Objects
Java Io Implementation of Unix/Linux "Tail -F"
Java Code to Convert Byte to Hexadecimal