"Java Alley"
by  Bruce Eckel
Web Techniques,  May 1997

Web Techniques grants permission to use these listings for private or
commercial use provided that credit to Web Techniques and the author is
maintained within the comments of the source. For questions, contact
editors@web-techniques.com.       

[LISTING ONE]

//: PassByValue.java
import java.util.*;
/**
 * Successful pass-by-value with clone()
*/
class Value implements Cloneable {
  int i;
  Value(int ii) { i = ii; }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println("Value can't clone");
    }
    return o;
  }
  public String toString() {
    return Integer.toString(i);
  }
}

public class PassByValue {
  static Value g(Value v) {
    // Pass by reference,
    // modifies outside object:
    v.i++;
    return v;
  }
  static Value f(Value v) {
    v = (Value)v.clone(); // Pass by value
    v.i++;
    return v;
  }
  public static void main(String args[]) {
    Value a = new Value(11);
    Value b = g(a);
    // Testing object equivalence,
    // not value equivalence:
    if(a == b) 
      System.out.println("a == b");
    else 
      System.out.println("a != b");
    System.out.println("a = " + a);
    System.out.println("b = " + b);
    Value c = new Value(47);
    Value d = f(c);
    if(c == d) 
      System.out.println("c == d");
    else 
      System.out.println("c != d");
    System.out.println("c = " + c);
    System.out.println("d = " + d);
  }
} ///:~

[LISTING TWO]

//: AddingClone.java
import java.util.*;
/**
 * You must go through a few gyrations to
 * add cloning to your own class.
*/
class Int2 implements Cloneable {
  private int i;
  public Int2(int ii) { i = ii; }
  public void increment() { i++; }
  public String toString() {
    return Integer.toString(i);
  }
  public Object clone() {
    Object o = null;
    try {
      o = super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println("Int2 can't clone");
    }
    return o;
  }
}

// Once it's cloneable, inheritance
// doesn't remove cloneability:
class Int3 extends Int2 {
  public Int3(int i) { super(i); }
}

public class AddingClone {
  public static void main(String args[]) {
    Int2 x = new Int2(10);
    Int2 x2 = (Int2)x.clone();
    x2.increment();
    System.out.println(
      "x = " + x + ", x2 = " + x2);
    // Anything inherited is also cloneable:
    Int3 x3 = new Int3(7);
    x3 = (Int3)x3.clone();

    Vector v = new Vector();
    for(int i = 0; i < 10; i++ )
      v.addElement(new Int2(i));
    System.out.println("v: " + v);
    Vector v2 = (Vector)v.clone();
    // Now clone each element:
    for(int i = 0; i < v.size(); i++)
      v2.setElementAt(
        ((Int2)v2.elementAt(i)).clone(), i);
    // Increment all v2's elements:
    for(Enumeration e = v2.elements();
        e.hasMoreElements(); )
      ((Int2)e.nextElement()).increment();
    // See if it's changed v's elements:
    System.out.println("v: " + v);
    System.out.println("v2: " + v2);
  }
} ///:~

[LISTING THREE]

//: HorrorFlick.java
import java.util.*;
/**
 * You can insert Cloneability at any
 * level of inheritance.
*/
class Person {}
class Hero extends Person {}
class Scientist extends Person 
    implements Cloneable {
  public Object clone() {
    try {
      return super.clone();
    } catch (CloneNotSupportedException e) {
      // this should never happen:
      // it's Cloneable already!
      throw new InternalError();
    }
  }
}
class MadScientist extends Scientist {}

public class HorrorFlick {
  public static void main(String args[]) {
    Person p = new Person();
    Hero h = new Hero();
    Scientist s = new Scientist();
    MadScientist m = new MadScientist();

    // p = (Person)p.clone(); // Compile error
    // h = (Hero)h.clone(); // Compile error
    s = (Scientist)s.clone();
    m = (MadScientist)m.clone();
  }
} ///:~