Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions

  




 

 

Thinking in Java
Prev Contents / Index Next

Cloning a composed object

There’s a problem you’ll encounter when trying to deep copy a composed object. You must assume that the clone( ) method in the member objects will in turn perform a deep copy on their references, and so on. This is quite a commitment. It effectively means that for a deep copy to work, you must either control all of the code in all of the classes, or at least have enough knowledge about all of the classes involved in the deep copy to know that they are performing their own deep copy correctly.

This example shows what you must do to accomplish a deep copy when dealing with a composed object:

//: appendixa:DeepCopy.java
// Cloning a composed object.
// {Depends: junit.jar}
import junit.framework.*;

class DepthReading implements Cloneable {
  private double depth;
  public DepthReading(double depth) { this.depth = depth; }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch(CloneNotSupportedException e) {
      e.printStackTrace();
    }
    return o;
  }
  public double getDepth() { return depth; }
  public void setDepth(double depth){ this.depth = depth; }
  public String toString() { return String.valueOf(depth);}
}

class TemperatureReading implements Cloneable {
  private long time;
  private double temperature;
  public TemperatureReading(double temperature) {
    time = System.currentTimeMillis();
    this.temperature = temperature;
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch(CloneNotSupportedException e) {
      e.printStackTrace();
    }
    return o;
  }
  public double getTemperature() { return temperature; }
  public void setTemperature(double temperature) {
    this.temperature = temperature;
  }
  public String toString() {
    return String.valueOf(temperature);
  }
}

class OceanReading implements Cloneable {
  private DepthReading depth;
  private TemperatureReading temperature;
  public OceanReading(double tdata, double ddata) {
    temperature = new TemperatureReading(tdata);
    depth = new DepthReading(ddata);
  }
  public Object clone() {
    OceanReading o = null;
    try {
      o = (OceanReading)super.clone();
    } catch(CloneNotSupportedException e) {
      e.printStackTrace();
    }
    // Must clone references:
    o.depth = (DepthReading)o.depth.clone();
    o.temperature =
      (TemperatureReading)o.temperature.clone();
    return o; // Upcasts back to Object
  }
  public TemperatureReading getTemperatureReading() {
    return temperature;
  }
  public void setTemperatureReading(TemperatureReading tr){
    temperature = tr;
  }
  public DepthReading getDepthReading() { return depth; }
  public void setDepthReading(DepthReading dr) {
    this.depth = dr;
  }
  public String toString() {
    return "temperature: " + temperature +
      ", depth: " + depth;
  }
}

public class DeepCopy extends TestCase {
  public DeepCopy(String name) { super(name); }
  public void testClone() {
    OceanReading reading = new OceanReading(33.9, 100.5);
    // Now clone it:
    OceanReading clone = (OceanReading)reading.clone();
    TemperatureReading tr = clone.getTemperatureReading();
    tr.setTemperature(tr.getTemperature() + 1);
    clone.setTemperatureReading(tr);
    DepthReading dr = clone.getDepthReading();
    dr.setDepth(dr.getDepth() + 1);
    clone.setDepthReading(dr);
    assertEquals(reading.toString(),
      "temperature: 33.9, depth: 100.5");
    assertEquals(clone.toString(),
      "temperature: 34.9, depth: 101.5");
  }
  public static void main(String[] args) {
    junit.textui.TestRunner.run(DeepCopy.class);
  }
} ///:~


DepthReading and TemperatureReading are quite similar; they both contain only primitives. Therefore, the clone( ) method can be quite simple: it calls super.clone( ) and returns the result. Note that the clone( ) code for both classes is identical.

OceanReading is composed of DepthReading and TemperatureReading objects and so, to produce a deep copy, its clone( ) must clone the references inside OceanReading. To accomplish this, the result of super.clone( ) must be cast to an OceanReading object (so you can access the depth and temperature references).
Thinking in Java
Prev Contents / Index Next


 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire