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

The effect of Object.clone( )

What actually happens when Object.clone( ) is called that makes it so essential to call super.clone( ) when you override clone( ) in your class? The clone( ) method in the root class is responsible for creating the correct amount of storage and making the bitwise copy of the bits from the original object into the new object’s storage. That is, it doesn’t just make storage and copy an Object; it actually figures out the size of the real object (not just the base-class object, but the derived object) that’s being copied and duplicates that. Since all this is happening from the code in the clone( ) method defined in the root class (that has no idea what’s being inherited from it), you can guess that the process involves RTTI to determine the actual object that’s being cloned. This way, the clone( ) method can create the proper amount of storage and do the correct bitwise copy for that type.

Whatever you do, the first part of the cloning process should normally be a call to super.clone( ). This establishes the groundwork for the cloning operation by making an exact duplicate. At this point you can perform other operations necessary to complete the cloning.

To know for sure what those other operations are, you need to understand exactly what Object.clone( ) buys you. In particular, does it automatically clone the destination of all the references? The following example tests this:

//: appendixa:Snake.java
// Tests cloning to see if destination
// of references are also cloned.
import com.bruceeckel.simpletest.*;

public class Snake implements Cloneable {
  private static Test monitor = new Test();
  private Snake next;
  private char c;
  // Value of i == number of segments
  public Snake(int i, char x) {
    c = x;
    if(--i > 0)
      next = new Snake(i, (char)(x + 1));
  }
  public void increment() {
    c++;
    if(next != null)
      next.increment();
  }
  public String toString() {
    String s = ":" + c;
    if(next != null)
      s += next.toString();
    return s;
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch(CloneNotSupportedException e) {
      System.err.println("Snake can't clone");
    }
    return o;
  }
  public static void main(String[] args) {
    Snake s = new Snake(5, 'a');
    System.out.println("s = " + s);
    Snake s2 = (Snake)s.clone();
    System.out.println("s2 = " + s2);
    s.increment();
    System.out.println("after s.increment, s2 = " + s2);
    monitor.expect(new String[] {
      "s = :a:b:c:d:e",
      "s2 = :a:b:c:d:e",
      "after s.increment, s2 = :a:c:d:e:f"
    });
  }
} ///:~


A Snake is made up of a bunch of segments, each of type Snake. Thus, it’s a singly linked list. The segments are created recursively, decrementing the first constructor argument for each segment until zero is reached. To give each segment a unique tag, the second argument, a char, is incremented for each recursive constructor call.

The increment( ) method recursively increments each tag so you can see the change, and the toString( ) recursively prints each tag. From the output, you can see that only the first segment is duplicated by Object.clone( ), therefore it does a shallow copy. If you want the whole snake to be duplicated—a deep copy—you must perform the additional operations inside your overridden clone( ).

You’ll typically call super.clone( ) in any class derived from a cloneable class to make sure that all of the base-class operations (including Object.clone( )) take place. This is followed by an explicit call to clone( ) for every reference in your object; otherwise those references will be aliased to those of the original object. It’s analogous to the way constructors are called: base-class constructor first, then the next-derived constructor, and so on, to the most-derived constructor. The difference is that clone( ) is not a constructor, so there’s nothing to make it happen automatically. You must make sure to do it yourself.
Thinking in Java
Prev Contents / Index Next


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