You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 34 Next »

When a nonfinal class defines a clone() method that does not call super.clone(), cloning a subtype will produce an object of the wrong type.

The Java API for the clone() method [API 2011] 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 does not call super.clone(). Hence, 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 result in a cloned object having the wrong type, with resulting unexpected or incorrect results when it is used.

Bibliography

  • No labels