Cloning and Covariance


Java allows you the ability to clone, or make a copy of, an object. You might find it surprising that cloning is only rarely a useful thing to do. In my numerous years of professional Java development, I've only seen a few needs for cloning. Therefore, I'm relegating cloning to a brief overview in this final section.

Unfortunately, cloning is often misunderstood and poorly implemented. If you have more sophisticated cloning needs than this simple example demonstrates, I refer you Effective Java[4] for an excellent discussion of the many issues related to cloning.

[4] [Bloch2001].

As an example, let's provide cloning capability for the simple class Course. The test is straightforward:

 public void testClone() {    final String department = "CHEM";    final String number = "400";    final Date now = new Date();    Course course = new Course(department, number);    course.setEffectiveDate(now);    Course copy = course.clone();    assertFalse(copy == course);    assertEquals(department, copy.getDepartment());    assertEquals(number, copy.getNumber());    assertEquals(now, copy.getEffectiveDate()); } 

Even though clone is defined on the class Object, the test won't compile. Object defines the clone method as protected. You must override the clone method in the Course subclass and make it public. The clone method is defined in Object as:

 protected native Object clone() throws CloneNotSupportedException; 

The native keyword in the signature indicates that the method is not implemented in Java but instead in the JVM.

To be able to clone an object, its class must implement the Cloneable interface. Cloneable is a marker interfaceit doesn't define clone, as you might expect. Instead, its goal is to prevent clients from cloning a class that was not explicitly designed to be cloneable.

The implementation in Course:

 package sis.studentinfo; ... public class Course implements java.io.Serializable, Cloneable {    private String department;    private String number;    private Date effectiveDate;    ...    @Override    public Course clone() {       Course copy = null;       try {          copy = (Course)super.clone();       }       catch (CloneNotSupportedException impossible) {          throw new RuntimeException("unable to clone");       }       return copy;    } } 

The first thing you might notice is that the clone method returns an object of the type Coursenot Object, as defined in the superclass. This is a capability of Java known as covariance. Covariance is the ability of a subclass method to return an object that is a subclass of the superclass return type. Cloning is the canonical example for covariance in Java.

The core of the clone method is the call to the superclass clone method. You always want to call the superclass clone method. The clone method as implemented in Object (in the VM actually) performs a bitwise copy of the contents of the object. This means that it copies values for every field defined on the class. References are copied as well, but the objects they refer to are not copied. For example, for the effectiveDate field in Course, both the original and the clone refer to the same Date object.

The default clone behavior, in which references are copied but not the objects to which they point, is known as a shallow clone. If you want a deep clonea copy where the contained objects are copied alsoyou must implement the details yourself in the clone method.

The call to super.clone can throw a CloneNotSupportedException. This is what requires your class to implement the Cloneable marker interface.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net