Skip to end of metadata
Go to start of metadata

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 (except Object) obey this convention, it will be the case that x.clone().getClass() == x.getClass().

Noncompliant Code Example

In this noncompliant code example, the clone() method in the class Base fails to call super.clone():

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:

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();
      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.

Automated Detection

ToolVersionCheckerDescription
SonarQube6.7S1182 

 

Bibliography