When a nonfinal class defines a clone()
method that fails to call super.clone()
, cloning a subclass of this class will produce an object of the wrong class.
The Java API [API 2011] for the clone()
method says:
By convention, the returned object should be obtained by calling
super.clone
. If a class and all of its superclasses (exceptObject
) obey this convention, it will be the case thatx.clone().getClass() == x.getClass()
.
Noncompliant Code Example
In this noncompliant code example, the clone()
method in the class Base
fails to call super.clone()
. For that reason, the object devClone
ends up being of type Base
instead of Derived
, with resulting incorrect application of the doLogic()
method.
class Base implements Cloneable { public Object clone() throws CloneNotSupportedException { return new Base(); } protected void doLogic() { System.out.println("Superclass doLogic"); } } class Derived extends Base { public Object clone() throws CloneNotSupportedException { return super.clone(); } protected void doLogic() { System.out.println("Subclass doLogic"); } public static void main(String[] args) { Derived dev = new Derived(); try { Base devClone = (Base)dev.clone(); // Has type Base instead of Derived devClone.doLogic(); // Prints "Superclass doLogic" instead of "Subclass doLogic" } catch (CloneNotSupportedException e) { /* ... */ } } }
Compliant Solution
This compliant solution correctly calls super.clone()
in the Base
class's clone()
method:
class Base implements Cloneable { public Object clone() throws CloneNotSupportedException { return super.clone(); } protected void doLogic() { System.out.println("Superclass doLogic"); } } class Derived extends Base { public Object clone() throws CloneNotSupportedException { return super.clone(); } protected void doLogic() { System.out.println("Subclass doLogic"); } public static void main(String[] args) { Derived dev = new Derived(); try { Base devClone = (Base)dev.clone(); // Has type Derived, as expected devClone.doLogic(); // Prints "Subclass doLogic", as expected } catch (CloneNotSupportedException e) { /* ... */ } } }
Applicability
Failing to call super.clone()
may cause a cloned object to have the wrong type, with unexpected or incorrect results when it is used.
Bibliography