Cloning a subclass a nonfinal class that defines a clone() method that fails to call super.clone() will produce an object of the wrong class.
The Java API [API 2013] 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 | ||
|---|---|---|
|
This is a stub. It needs an example of an error caused due to using the Base class's object where the subclass's object was expected. It should not produce a RuntimeException (ClassCastException) to qualify.
| Code Block |
|---|
class Base implements Cloneable { public Object clone() throws CloneNotSupportedException { return new Base(); } protected static void doLogic() { System.out.println("Superclass doLogic"); } } class Subclass1Derived extends Base { public Object clone() throws CloneNotSupportedException { return super.clone(); } protected static void doLogic() { System.out.println("Subclass doLogic"); } public static void main(String[] args) { Subclass1Derived sdev = new Subclass1Derived(); try { ObjectBase scdevClone = s(Base)dev.clone(); // get's Base objHas type Base instead of Derived devClone.doLogic(); // Prints "Superclass doLogic" instead of subclass' "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(sc.getClass().hashCode()); // a possible mistake"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 { // Has type Derived, as expected //Base devClone = (Base)dev.clone(Subclass1)sc)); devClone.doLogic(); // Produces ClassCastException, disqualified Prints "Subclass doLogic" as expected } catch (CloneNotSupportedException e) { /* ... */ } } } |
Applicability
Failing to call super.clone() may cause a cloned object to have the wrong type.
Automated Detection
| Tool | Version | Checker | Description | ||||||
|---|---|---|---|---|---|---|---|---|---|
| CodeSonar |
| JAVA.CLASS.CLONE.CCSM JAVA.CLASS.MCS | Clone call to super is missing Missing call to super | ||||||
| Parasoft Jtest |
| CERT.MET53.SCLONE | Call 'super.clone()' in all 'clone()' methods | ||||||
| SonarQube |
| S1182 |
Bibliography
...
MET34-J. Follow the general contract when implementing the compareTo method 10. Methods (MET) 11. Exceptional Behavior (EXC)