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

Successful cloning

Once you understand the details of implementing the clone( ) method, you’re able to create classes that can be easily duplicated to provide a local copy:

//: appendixa:LocalCopy.java
// Creating local copies with clone().
import com.bruceeckel.simpletest.*;
import java.util.*;

class MyObject implements Cloneable {
  private int n;
  public MyObject(int n) { this.n = n; }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch(CloneNotSupportedException e) {
      System.err.println("MyObject can't clone");
    }
    return o;
  }
  public int getValue() { return n; }
  public void setValue(int n) { this.n = n; }
  public void increment() { n++; }
  public String toString() { return Integer.toString(n); }
}

public class LocalCopy {
  private static Test monitor = new Test();
  public static MyObject g(MyObject v) {
    // Passing a reference, modifies outside object:
    v.increment();
    return v;
  }
  public static MyObject f(MyObject v) {
    v = (MyObject)v.clone(); // Local copy
    v.increment();
    return v;
  }
  public static void main(String[] args) {
    MyObject a = new MyObject(11);
    MyObject b = g(a);
    // Reference equivalence, not object equivalence:
    System.out.println("a == b: " + (a == b) +
      "\na = " + a + "\nb = " + b);
    MyObject c = new MyObject(47);
    MyObject d = f(c);
    System.out.println("c == d: " + (c == d) +
      "\nc = " + c + "\nd = " + d);
    monitor.expect(new String[] {
      "a == b: true",
      "a = 12",
      "b = 12",
      "c == d: false",
      "c = 47",
      "d = 48"
    });
  }
} ///:~


First of all, for clone( ) to be accessible, you must make it public. Second, for the initial part of your clone( ) operation, you should call the base-class version of clone( ). The clone( ) that’s being called here is the one that’s predefined inside Object, and you can call it because it’s protected and thereby accessible in derived classes.

Object.clone( ) figures out how big the object is, creates enough memory for a new one, and copies all the bits from the old to the new. This is called a bitwise copy, and is typically what you’d expect a clone( ) method to do. But before Object.clone( ) performs its operations, it first checks to see if a class is Cloneable—that is, whether it implements the Cloneable interface. If it doesn’t, Object.clone( ) throws a CloneNotSupportedException to indicate that you can’t clone it. Thus, you’ve got to surround your call to super.clone( ) with a try block to catch an exception that should never happen (because you’ve implemented the Cloneable interface).

In LocalCopy, the two methods g( ) and f( ) demonstrate the difference between the two approaches for argument passing. The g( ) method shows passing by reference in which it modifies the outside object and returns a reference to that outside object, whereas f( ) clones the argument, thereby decoupling it and leaving the original object alone. It can then proceed to do whatever it wants—even return a reference to this new object without any ill effects to the original. Notice the somewhat curious-looking statement:

v = (MyObject)v.clone();


This is where the local copy is created. To prevent confusion by such a statement, remember that this rather strange coding idiom is perfectly feasible in Java because every object identifier is actually a reference. So the reference v is used to clone( ) a copy of what it refers to, and this returns a reference to the base type Object (because it’s defined that way in Object.clone( )) that must then be cast to the proper type.

In main( ), the difference between the effects of the two different argument-passing approaches is tested. It’s important to notice that the equivalence tests in Java do not look inside the objects being compared to see if their values are the same. The == and != operators are simply comparing the references. If the addresses inside the references are the same, the references are pointing to the same object and are therefore “equal.” So what the operators are really testing is whether the references are aliased to the same object!
Thinking in Java
Prev Contents / Index Next


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