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' System.out.println(sc.getClass().hashCode()); // a possible mistake "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 { // 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 | ||||||
---|---|---|---|---|---|---|---|---|---|
Parasoft Jtest |
| CERT.MET53.SCLONE | Call 'super.clone()' in all 'clone()' methods | ||||||
SonarQube |
| S1182 |
Bibliography
...
MET14-J. Follow the general contract when implementing the compareTo method 12. Methods (MET) MET36-J. Do not use deprecated or obsolete methods