| Making a copy of an object seems at first to be a straight forward 
              task:   
             Simply copy the values of all the properties into another 
              instance of the same class. But what about the variables that are references to 
              other objects? Copies of these reference values mean they will point 
              to the same objects as the first class.  But maybe that is not what we want. Perhaps we want 
              all the objects referenced by the copy to be independent copies 
              as well.  These two types of object copies are called:  
             
              shallow copy - exact bit copy of all the attributes of the original 
                object deep copy - primitives are copied exactly but objects referenced 
                are copied rather than the references themselves. The Object 
              class, which is inherited by all Java classes, includes the clone() 
              method that will make exact bit copies of all the properties. 
             However, clone() 
              is a protected 
              method. So a given object can not be cloned by instances of any 
              classes outside the package (unless they are subclasses of that 
              object's class). This allows the class designer to specify explicitly 
              what kind of clones (shallow or deep) to make. Java requires classes that want to override the clone() 
              method, to implement the cloneable 
              interface. The clone() 
              method must be made public 
              as well so as to override the access restrictions.  For example, the HashTable 
              class implements cloneable. 
              Its clone() 
              method makes a shallow copy so the keys and values of the copied 
              HashTable will reference the same objects as the original.  Many core Java classes, however, do not implement 
              cloneable. 
              If the clone() 
              method is invoked for such classes, a CloneNotSupportedException 
              will result.  
              
                 
                  | Example.java |   
                  |  
                       import 
                        java.util.*;
 /** Illustrate cloning instances of a class. **/
 public class Example implements Cloneable {
 int fNum;
 Integer [] fIarray;
 
 Example (int nElements) {
 fNum = nElements;
 fIarray = new Integer[fNum];
 
 // Set the array to random values
 Random ran = new Random ();
 for (int i=0; i < fNum; i++){
 fIarray[i] = new Integer 
                        (ran.nextInt (10000));
 }
 
 } // const
 
 public Object clone () {
 try  {
 return super.clone 
                        ();
 }
 catch (CloneNotSupportedException 
                        e) {
 throw new Error ("This 
                        should never happen!");
 }
 } // clone
 
 public static void main (String [] args)
 {
 Example ex   =  new 
                        Example (5);
 Example copy =  (Example)ex.clone 
                        ();
 
 // Change a value in the original 
                        array.
 ex.fIarray[0] = new Integer (1234567);
 
 // Then the copy's value also 
                        changes since it references
 // the same array.
 System.out.println ("Original 
                        iarray[0] = " + ex.fIarray[0]);
 System.out.println ("Copy     
                        iarray[0] = " + copy.fIarray[0]);
 } // main
 
 } // Example
 |   
                  | ExampleDeep.java |   
                  | /** Illustrate 
                      cloning a subclass of a cloneable class. **/public class ExampleDeep extends Example {
 
 ExampleDeep (int num) {
 super (num);
 } // const
 
 public Object clone () {
 
 // First make exact bitwise copy
 ExampleDeep copy =  (ExampleDeep)super.clone 
                      ();
 
 // A new array of references to 
                      Integer objects
 // is created
 copy.fIarray = new Integer[copy.fNum];
 
 // Then the new Integer objects 
                      given same internal
 // values as the original
 for (int i=0; i < copy.fNum; i++) 
                      {
 copy.fIarray[i] =
 new 
                      Integer (fIarray[i].intValue ());
 }
 return copy;
 } // clone
 
 public static void main (String [] args)
 {
 ExampleDeep ex   =  new 
                      ExampleDeep (5);
 ExampleDeep copy =  (ExampleDeep) 
                      ex.clone ();
 
 // Change a value in the original 
                      array.
 ex.fIarray[0] = new Integer (1234567);
 
 // But  the copy's value 
                      unchanged since it references
 // a different array.
 System.out.println ("Original iarray[0] 
                      = " + ex.fIarray[0]);
 System.out.println ("Copy     
                      iarray[0] = " + copy.fIarray[0]);
 
 } // main
 
 } // ExampleDeep
 |    For the Example 
              case:  c:\> java ExampleOriginal iarray[0] = 1234567
 Copy iarray[0] = 1234567
 While for the DeepExample 
              case, a typical run goes as: c:\> java ExampleOriginal iarray[0] = 1234567
 Copy iarray[0] = 1930
 We see that the deep copy creates a separate array of Integer 
              objects.  Applet Cloning Demo The following applet illustrates the same techniques 
              
                 
                  | CloningJApplet8
 Illustrates these same concepts in a graphical interface.
 |   
                  |  import 
                      javax.swing.*;import java.awt.*;
 import java.awt.event.*;
 import java.util.*;
 
 /** Include Outputable interface if needed. **/
 public class CloningJApplet8 extends JApplet
 implements ActionListener
 {
 // A Swing fTextArea for display of string info
 JTextArea fTextArea ;
 
 // Flag for whether the applet is in a browser
 // or running via the main () below.
 boolean fInBrowser = true;
 
 ShallowClass fShallowClass;
 DeepClass fDeepClass;
 
 public void init () {
 
 // Create a User Interface with 
                      a TextArea with sroll bars
 // and a Go button to initiate processing 
                      and a Clear button
 // to clear the TextArea.
 
 JPanel panel = new JPanel (new BorderLayout 
                      ());
 
 // Create an instance of a fTextArea
 fTextArea = new JTextArea ();
 fTextArea.setEditable (false);
 
 // Add to a scroll pane so that 
                      a long list of
 // computations can be seen.
 JScrollPane area_scroll_pane = new 
                      JScrollPane (fTextArea);
 
 panel.add (area_scroll_pane,"Center");
 
 JButton go_button = new JButton 
                      ("Shallow");
 go_button.addActionListener (this);
 
 JButton clear_button = new JButton 
                      ("Deep");
 clear_button.addActionListener (this);
 
 JButton exit_button = new JButton 
                      ("Exit");
 exit_button.addActionListener (this);
 
 JPanel control_panel = new JPanel 
                      ();
 control_panel.add (go_button);
 control_panel.add (clear_button);
 control_panel.add (exit_button);
 
 panel.add (control_panel,"South");
 // Add text area with scrolling 
                      to the content pane.
 add (panel);
 
 } // init
 
 // Can use the start () method, which is called 
                      after
 // init () and the display has been created.
 public void start () {
 // Put task code here that will 
                      generate text
 // for the fTextArea.
 } // start
 
 public void actionPerformed (ActionEvent e) 
                      {
 String source = e.getActionCommand 
                      ();
 if ( source.equals ("Shallow"))
 shallowClone 
                      ();
 else if ( source.equals ("Deep") 
                      )
 deepClone 
                      ();
 else if (!fInBrowser)
 System.exit 
                      (0);
 } // actionPerformed
 
 public void shallowClone () {
 ShallowClass copy;
 
 fShallowClass = new ShallowClass 
                      (5);
 copy =  (ShallowClass)fShallowClass.clone 
                      ();
 
 // Modify original data
 fShallowClass.setData (4, 1234567);
 output ("Original = ", fShallowClass);
 output ("Clone    = 
                      ", copy);
 } // shallowClone
 
 public void deepClone () {
 DeepClass copy;
 fDeepClass = new DeepClass (5);
 
 copy =  (DeepClass)fDeepClass.clone 
                      ();
 
 // Modify original data
 fDeepClass.setData (4, 12345767);
 output ("Original = ", fDeepClass);
 output ("Clone    = 
                      ", copy);
 
 } // deepClone
 
 public void output (String str, ShallowClass 
                      obj) {
 fTextArea.append (str);
 Integer [] data = obj.getData ();
 for (int i=0; i < 5; i++)
 fTextArea.append (data[i]+" 
                      ");
 fTextArea.append ("\n");
 } // output
 
 public static void main (String[] args) {
 // *** Modify these values for the 
                      particular program.
 int frame_width=350;
 int frame_height=350;
 
 // *** Modify applet subclass name 
                      to that of the program
 CloningJApplet8 applet = new CloningJApplet8 
                      ();
 applet.fInBrowser = false;
 
 // Note that init () invoked before 
                      adding to frame.
 // So don't use width/height info 
                      in init () since those
 // parameters not yet set.
 applet.init ();
 
 // Following anonymous class used 
                      to close window & exit program
 JFrame f = new JFrame ("Frame & 
                      Image Demo");
 f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
 // Add applet to the frame
 
 f.getContentPane ().add (applet);
 f.setSize (new Dimension (frame_width,frame_height));
 f.setVisible (true);
 }
 } // main
 
 class ShallowClass implements Cloneable {
 
 Integer [] fData = null;
 int fNumData = 5;
 
 ShallowClass ()
 {}
 
 ShallowClass (int num) {
 fNumData = num;
 makeData ();
 }
 
 ShallowClass (Integer [] dat) {
 fData = dat;
 }
 
 void makeData () {
 Random ran = new Random ();
 fData = new Integer[fNumData];
 for (int i=0; i < fNumData; i++)
 {
 fData[i] = new Integer 
                      (ran.nextInt (10000));
 }
 } // makeData
 
 Integer [] getData () {
 return fData;
 }
 
 void setData (int element, int val) {
 if (element < fNumData)
 fData[element] = new 
                      Integer (val);
 }
 
 public Object clone (){
 try {
 // The clone's data 
                      is same as the original
 return  (ShallowClass)super.clone 
                      ();
 }
 catch  (CloneNotSupportedException 
                      e ) {
 throw new Error ("This 
                      should never happen!");
 }
 }
 } // ShallowClass
 
 class DeepClass extends ShallowClass {
 DeepClass ()
 { }
 
 DeepClass (int num)
 { super (num); }
 
 DeepClass (Integer [] dat)
 { super (dat);}
 
 void setData (Integer [] dat)
 { fData = dat;}
 
 public Object clone (){
 // First make copy of the data
 Integer [] clone_data = new Integer[fNumData];
 for (int i=0; i < fNumData; i++) 
                      {
 // New Integer objects 
                      but same values
 clone_data[i] = new 
                      Integer (fData[i].intValue () );
 }
 
 // Create a new instance of DeepClass 
                      with
 // the new data array.
 
 DeepClass copy =  (DeepClass)super.clone 
                      ();
 copy.setData (clone_data);
 return copy;
 } // clone
 
 } // DeepClass
 |      Most recent update: Sept. 16, 2005 |