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()
:
Code Block | ||
---|---|---|
| ||
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) { /* ... */ } } } |
Consequently, the object devClone
ends up being of type Base
instead of Derived
and the doLogic()
method is incorrectly applied.
Compliant Solution
This compliant solution correctly calls super.clone()
in the Base
class's clone()
method:
Code Block | ||
---|---|---|
| ||
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