Java Tutorial/Class Definition/Clone

Материал из Java эксперт
Перейти к: навигация, поиск

A collection of utilities to workaround limitations of Java clone framework

/*
 * $HeadURL$
 * $Revision$
 * $Date$
 *
 *
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 */
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * A collection of utilities to workaround limitations of Java clone framework.
 */
public class CloneUtils {
    public static Object clone(final Object obj) throws CloneNotSupportedException {
        if (obj == null) {
            return null;
        }
        if (obj instanceof Cloneable) {
            Class<?> clazz = obj.getClass ();
            Method m;
            try {
                m = clazz.getMethod("clone", (Class[]) null);
            } catch (NoSuchMethodException ex) {
                throw new NoSuchMethodError(ex.getMessage());
            }
            try {
                return m.invoke(obj, (Object []) null);
            } catch (InvocationTargetException ex) {
                Throwable cause = ex.getCause();
                if (cause instanceof CloneNotSupportedException) {
                    throw ((CloneNotSupportedException) cause); 
                } else {
                    throw new Error("Unexpected exception", cause);
                }
            } catch (IllegalAccessException ex) {
                throw new IllegalAccessError(ex.getMessage());
            }
        } else {
            throw new CloneNotSupportedException();
        }
    }
    
    /**
     * This class should not be instantiated.
     */
    private CloneUtils() {
    }
}





Arrays are automatically cloneable

public class Main {
  public static void main(String[] argv) throws Exception {
    int[] ints = new int[] { 123, 234 };
    int[] intsClone = (int[]) ints.clone();
  }
}





Cast after cloning

class A {
  int l = 1;
}
class B extends A implements Cloneable {
  int m = 2;
}
class CloneDemo3 extends B {
  int n = 3;
  A a = new A();
  public static void main(String[] args) throws CloneNotSupportedException {
    CloneDemo3 c = new CloneDemo3();
    CloneDemo3 c2 = (CloneDemo3) c.clone();
    System.out.println(c.l);
    System.out.println(c2.l);
    System.out.println(c.m);
    System.out.println(c2.m);
    System.out.println(c.n);
    System.out.println(c2.n);
    System.out.println(c.a == c2.a);
  }
}





Clone an array

/* 
 * Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *
 */

/**
 * @author Stephen Colebourne
 * @author Moritz Petersen
 * @author 
 * @author Maarten Coene
 * @since 2.0
 * @version $Id: ArrayUtils.java 632503 2008-03-01 00:21:52Z ggregory $
 */
public class Main {
  // Clone
  //-----------------------------------------------------------------------
  /**
   * Shallow clones an array returning a typecast result and handling
   * <code>null</code>.
   *
   * The objects in the array are not cloned, thus there is no special
   * handling for multi-dimensional arrays.
   * 
   * This method returns <code>null</code> for a <code>null</code> input array.
   * 
   * @param array  the array to shallow clone, may be <code>null</code>
   * @return the cloned array, <code>null</code> if <code>null</code> input
   */
  public static Object[] clone(Object[] array) {
      if (array == null) {
          return null;
      }
      return (Object[]) array.clone();
  }
  /**
   * Clones an array returning a typecast result and handling
   * <code>null</code>.
   *
   * This method returns <code>null</code> for a <code>null</code> input array.
   * 
   * @param array  the array to clone, may be <code>null</code>
   * @return the cloned array, <code>null</code> if <code>null</code> input
   */
  public static long[] clone(long[] array) {
      if (array == null) {
          return null;
      }
      return (long[]) array.clone();
  }
  /**
   * Clones an array returning a typecast result and handling
   * <code>null</code>.
   *
   * This method returns <code>null</code> for a <code>null</code> input array.
   * 
   * @param array  the array to clone, may be <code>null</code>
   * @return the cloned array, <code>null</code> if <code>null</code> input
   */
  public static int[] clone(int[] array) {
      if (array == null) {
          return null;
      }
      return (int[]) array.clone();
  }
  /**
   * Clones an array returning a typecast result and handling
   * <code>null</code>.
   *
   * This method returns <code>null</code> for a <code>null</code> input array.
   * 
   * @param array  the array to clone, may be <code>null</code>
   * @return the cloned array, <code>null</code> if <code>null</code> input
   */
  public static short[] clone(short[] array) {
      if (array == null) {
          return null;
      }
      return (short[]) array.clone();
  }
  /**
   * Clones an array returning a typecast result and handling
   * <code>null</code>.
   *
   * This method returns <code>null</code> for a <code>null</code> input array.
   * 
   * @param array  the array to clone, may be <code>null</code>
   * @return the cloned array, <code>null</code> if <code>null</code> input
   */
  public static char[] clone(char[] array) {
      if (array == null) {
          return null;
      }
      return (char[]) array.clone();
  }
  /**
   * Clones an array returning a typecast result and handling
   * <code>null</code>.
   *
   * This method returns <code>null</code> for a <code>null</code> input array.
   * 
   * @param array  the array to clone, may be <code>null</code>
   * @return the cloned array, <code>null</code> if <code>null</code> input
   */
  public static byte[] clone(byte[] array) {
      if (array == null) {
          return null;
      }
      return (byte[]) array.clone();
  }
  /**
   * Clones an array returning a typecast result and handling
   * <code>null</code>.
   *
   * This method returns <code>null</code> for a <code>null</code> input array.
   * 
   * @param array  the array to clone, may be <code>null</code>
   * @return the cloned array, <code>null</code> if <code>null</code> input
   */
  public static double[] clone(double[] array) {
      if (array == null) {
          return null;
      }
      return (double[]) array.clone();
  }
  /**
   * Clones an array returning a typecast result and handling
   * <code>null</code>.
   *
   * This method returns <code>null</code> for a <code>null</code> input array.
   * 
   * @param array  the array to clone, may be <code>null</code>
   * @return the cloned array, <code>null</code> if <code>null</code> input
   */
  public static float[] clone(float[] array) {
      if (array == null) {
          return null;
      }
      return (float[]) array.clone();
  }
  /**
   * Clones an array returning a typecast result and handling
   * <code>null</code>.
   *
   * This method returns <code>null</code> for a <code>null</code> input array.
   * 
   * @param array  the array to clone, may be <code>null</code>
   * @return the cloned array, <code>null</code> if <code>null</code> input
   */
  public static boolean[] clone(boolean[] array) {
      if (array == null) {
          return null;
      }
      return (boolean[]) array.clone();
  }
}





Clone an object with clone method from parent

public class Main {
  public static void main(String[] args) {
    try {
      Employee e = new Employee("Dolly", 1000);
      System.out.println(e);
      System.out.println("The employee"s name is " + e.getName());
      System.out.println("The employees"s pay is " + e.getSalary());
      Employee eClone = (Employee) e.clone();
      System.out.println(eClone);
      System.out.println("The clone"s name is " + eClone.getName());
      System.out.println("The clones"s pay is " + eClone.getSalary());
      eClone.setName("Polly");
      eClone.setSalary(2000);
      System.out.println("The employee"s name is " + e.getName());
      System.out.println("The employees"s pay is " + e.getSalary());
      System.out.println("The clone"s name is " + eClone.getName());
      System.out.println("The clones"s pay is " + eClone.getSalary());
    } catch (Exception e) {
      System.out.println("Exception " + e);
    }
  }
}
class Employee implements Cloneable {
  private StringBuffer name;
  private int salary;
  public Employee(String name, int salary) {
    this.name = new StringBuffer(name);
    this.salary = salary;
  }
  public Employee() {
  }
  public Object clone() throws CloneNotSupportedException {
    try {
      return super.clone();
    } catch (CloneNotSupportedException cnse) {
      System.out.println("CloneNotSupportedException thrown " + cnse);
      throw new CloneNotSupportedException();
    }
  }
  public String getName() {
    return name.toString();
  }
  public void setName(String name) {
    this.name.delete(0, this.name.length());
    this.name.append(name);
  }
  public void setSalary(int salary) {
    this.salary = salary;
  }
  public int getSalary() {
    return this.salary;
  }
}





Construct clone of an object

class Box {
  double width;
  double height;
  double depth;
  Box(Box ob) { 
    width = ob.width;
    height = ob.height;
    depth = ob.depth;
  }
  Box(double w, double h, double d) {
    width = w;
    height = h;
    depth = d;
  }
  Box() {
    width = -1; 
    height = -1;
    depth = -1; 
  }
  Box(double len) {
    width = height = depth = len;
  }
  double volume() {
    return width * height * depth;
  }
}
class BoxWeight extends Box {
  double weight; 
  BoxWeight(double w, double h, double d, double m) {
    width = w;
    height = h;
    depth = d;
    weight = m;
  }
}
class DemoBoxWeight {
  public static void main(String args[]) {
    BoxWeight mybox1 = new BoxWeight(10, 20, 15, 34.3);
    BoxWeight mybox2 = new BoxWeight(2, 3, 4, 0.076);
    double vol;
    vol = mybox1.volume();
    System.out.println(vol);
    System.out.println(mybox1.weight);
    System.out.println();
    vol = mybox2.volume();
    System.out.println(vol);
    System.out.println(mybox2.weight);
  }
}





construct clone of an object and call constructor in the super class

class Box {
  private double width;
  private double height;
  private double depth;
  Box(Box ob) { 
    width = ob.width;
    height = ob.height;
    depth = ob.depth;
  }
  Box(double w, double h, double d) {
    width = w;
    height = h;
    depth = d;
  }
  Box() {
    width = -1; 
    height = -1;
    depth = -1; 
  }
  Box(double len) {
    width = height = depth = len;
  }
  double volume() {
    return width * height * depth;
  }
}
class BoxWeight extends Box {
  double weight;
  BoxWeight(BoxWeight ob) { 
    super(ob);
    weight = ob.weight;
  }
  BoxWeight(double w, double h, double d, double m) {
    super(w, h, d); 
    weight = m;
  }
  BoxWeight() {
    super();
    weight = -1;
  }
  BoxWeight(double len, double m) {
    super(len);
    weight = m;
  }
}
class DemoSuper {
  public static void main(String args[]) {
    BoxWeight mybox1 = new BoxWeight(10, 20, 15, 34.3);
    BoxWeight mybox2 = new BoxWeight(2, 3, 4, 0.076);
    BoxWeight mybox3 = new BoxWeight();
    BoxWeight mycube = new BoxWeight(3, 2);
    BoxWeight myclone = new BoxWeight(mybox1);
    double vol;
    vol = mybox1.volume();
    System.out.println("Volume of mybox1 is " + vol);
    System.out.println("Weight of mybox1 is " + mybox1.weight);
    System.out.println();
    vol = mybox2.volume();
    System.out.println("Volume of mybox2 is " + vol);
    System.out.println("Weight of mybox2 is " + mybox2.weight);
    System.out.println();
    vol = mybox3.volume();
    System.out.println("Volume of mybox3 is " + vol);
    System.out.println("Weight of mybox3 is " + mybox3.weight);
    System.out.println();
    vol = myclone.volume();
    System.out.println("Volume of myclone is " + vol);
    System.out.println("Weight of myclone is " + myclone.weight);
    System.out.println();
    vol = mycube.volume();
    System.out.println("Volume of mycube is " + vol);
    System.out.println("Weight of mycube is " + mycube.weight);
    System.out.println();
  }
}





Copy an serializable object deeply

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
public class Main {
  // ///////////////////////////////////////////////////////////////////////
  // Cloning Methods //
  // ///////////////////////////////////////////////////////////////////////
  /**
   * Copy an serializable object deeply.
   * 
   * @param obj
   *          Object to copy.
   * @return Copied object.
   * 
   * @throws IOException
   * @throws ClassNotFoundException
   */
  public static Object copy(final Serializable obj) throws IOException, ClassNotFoundException {
    ObjectOutputStream out = null;
    ObjectInputStream in = null;
    Object copy = null;
    try {
      // write the object
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      out = new ObjectOutputStream(baos);
      out.writeObject(obj);
      out.flush();
      // read in the copy
      byte data[] = baos.toByteArray();
      ByteArrayInputStream bais = new ByteArrayInputStream(data);
      in = new ObjectInputStream(bais);
      copy = in.readObject();
    } finally {
      out.close();
      in.close();
    }
    return copy;
  }
}





Copying Objects implements Cloneable

class Flea implements Cloneable {
  public Flea() {
  }
  public void setName(String aName) {
    name = aName;
  }
  public String getName() {
    return name;
  }
  public String getSpecies() {
    return species;
  }
  public void sound() {
    System.out.println("Psst");
  }
  public String toString() {
    return super.toString() + "\nIt"s " + name + " the " + species;
  }
  public Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
  private String name;
  private String species;
}
public class MainClass {
  public static void main(String[] args) {
    try {
      Flea myPet = new Flea();
      myPet.setName("my name");
      Flea yourPet = (Flea) myPet.clone();
      yourPet.setName("Gnasher");
      System.out.println("\nYour pet details:\n" + yourPet);
      System.out.println("\nMy pet details:\n" + myPet);
    } catch (CloneNotSupportedException e) {
      e.printStackTrace(System.err);
    }
  }
}



Your pet details:
Flea@360be0
It"s Gnasher the null
My pet details:
Flea@45a877
It"s my name the null


Deep clone Object

/*
 * Copyright (C) 2001-2003 Colin Bell
 * colbell@users.sourceforge.net
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
import java.io.*;
import java.text.NumberFormat;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * General purpose utilities functions.
 *
 * @author 
 */
public class Utilities
{
  
  /**
   * Creates a clone of any serializable object. Collections and arrays
   * may be cloned if the entries are serializable.
   *
   * Caution super class members are not cloned if a super class is not serializable.
   */
  public static Object cloneObject(Object toClone, final ClassLoader classLoader)
  {
     if(null == toClone)
     {
        return null;
     }
     else
     {
        try
        {
           ByteArrayOutputStream bOut = new ByteArrayOutputStream();
           ObjectOutputStream oOut = new ObjectOutputStream(bOut);
           oOut.writeObject(toClone);
           oOut.close();
           ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray());
           bOut.close();
           ObjectInputStream oIn = new ObjectInputStream(bIn)
           {
              protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException
              {
                return Class.forName(desc.getName(), false, classLoader);
              }
           };
           bIn.close();
           Object copy = oIn.readObject();
           oIn.close();
           return copy;
        }
        catch (Exception e)
        {
           throw new RuntimeException(e);
        }
     }
  }
}





Deep clone serializing/de-serializng Clone

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
 * Utility for object cloning
 * 
 * @author 
 */
public class CloneUtil
{
    /**
     * Provides a deep clone serializing/de-serializng <code>objToClone</code>     
     * 
     * @param objToClone The object to be cloned
     * @return The cloned object
     */
    public static final Object deepClone(Object objToClone)
    {
        try
        {
            ByteArrayOutputStream bytearrayoutputstream = new ByteArrayOutputStream(100);
            ObjectOutputStream objectoutputstream = new ObjectOutputStream(bytearrayoutputstream);
            objectoutputstream.writeObject(objToClone);
            byte abyte0[] = bytearrayoutputstream.toByteArray();
            objectoutputstream.close();
            ByteArrayInputStream bytearrayinputstream = new ByteArrayInputStream(abyte0);
            ObjectInputStream objectinputstream = new ObjectInputStream(bytearrayinputstream);
            Object clone = objectinputstream.readObject();
            objectinputstream.close();
            return clone;
        }
        catch (Exception exception)
        {
            // nothing
        }
        return null;
    }
}





Demonstrate the clone() method.

class TestClone implements Cloneable {
  int a;
  double b;
  TestClone cloneTest() {
    try {
      return (TestClone) super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println("Cloning not allowed.");
      return this;
    }
  }
}
class CloneDemo {
  public static void main(String args[]) {
    TestClone x1 = new TestClone();
    TestClone x2;
    x1.a = 10;
    x1.b = 20.98;
    x2 = x1.cloneTest(); // clone x1
    System.out.println("x1: " + x1.a + " " + x1.b);
    System.out.println("x2: " + x2.a + " " + x2.b);
  }
}





Manipulate properties after clone operation

public class Main {
  public static void main(String[] args) {
    try {
      Employee e = new Employee("B", 1000);
      System.out.println(e);
      System.out.println("The employee"s name is " + e.getName());
      System.out.println("The employees"s pay is " + e.getSalary());
      Employee eClone = (Employee) e.clone();
      System.out.println(eClone);
      System.out.println("The clone"s name is " + eClone.getName());
      System.out.println("The clones"s pay is " + eClone.getSalary());
      eClone.setName("A");
      eClone.setSalary(2000);
      System.out.println("The employee"s name is " + e.getName());
      System.out.println("The employees"s pay is " + e.getSalary());
      System.out.println("The clone"s name is " + eClone.getName());
      System.out.println("The clones"s pay is " + eClone.getSalary());
    } catch (Exception e) {
      System.out.println("Exception " + e);
    }
  }
}
class Employee implements Cloneable {
  private StringBuffer name;
  private int salary;
  public Employee(String name, int salary) {
    this.name = new StringBuffer(name);
    this.salary = salary;
  }
  public Employee() {
  }
  public Object clone() throws CloneNotSupportedException {
    try {
      Employee o = (Employee) super.clone();
      o.name = new StringBuffer(name.toString());
      return o;
    } catch (CloneNotSupportedException cnse) {
      System.out.println("CloneNotSupportedException thrown " + cnse);
      throw new CloneNotSupportedException();
    }
  }
  public String getName() {
    return name.toString();
  }
  public void setName(String name) {
    this.name.delete(0, this.name.length());
    this.name.append(name);
  }
  public void setSalary(int salary) {
    this.salary = salary;
  }
  public int getSalary() {
    return this.salary;
  }
}





Override the clone() method.

class TestClone implements Cloneable {
  int a;
  double b;
  public Object clone() {
    try {
      return super.clone();
    } catch (CloneNotSupportedException e) {
      System.out.println("Cloning not allowed.");
      return this;
    }
  }
}
class CloneDemo2 {
  public static void main(String args[]) {
    TestClone x1 = new TestClone();
    TestClone x2;
    x1.a = 10;
    x1.b = 20.98;
    x2 = (TestClone) x1.clone();
    System.out.println("x1: " + x1.a + " " + x1.b);
    System.out.println("x2: " + x2.a + " " + x2.b);
  }
}





public Object clone() throws CloneNotSupportedException

public class Main {
  public static void main(String[] args) throws CloneNotSupportedException {
    CloneDemo2 cd2 = new CloneDemo2();
    System.out.println(cd2.salary);
    AnotherClass ac = new AnotherClass();
    System.out.println(ac.gradeLetter);
    AnotherClass y = (AnotherClass) ac.clone();
    System.out.println(y.gradeLetter);
  }
}
class CloneDemo2 implements Cloneable {
  double salary = 50000.0;
}
class AnotherClass implements Cloneable {
  char gradeLetter = "C";
  public Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
}





Serializable Clone

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public abstract class SerializableClone {
  public static Object clone(final Object obj) throws Exception {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ObjectOutputStream oout = new ObjectOutputStream(out);
    oout.writeObject(obj);
    ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(out.toByteArray()));
    return in.readObject();
  }
}





Shallow copy then deep copy

class A {
  int l = 1;
}
class B extends A implements Cloneable {
  int m = 2;
}
class CloneDemo4 extends B {
  int n = 3;
  A a = new A();
  public static void main(String[] args) throws CloneNotSupportedException {
    CloneDemo4 c = new CloneDemo4();
    CloneDemo4 c2 = (CloneDemo4) c.clone();
    System.out.println(c.l);
    System.out.println(c2.l);
    System.out.println(c.m);
    System.out.println(c2.m);
    System.out.println(c.n);
    System.out.println(c2.n);
    System.out.println(c.a == c2.a);
  }
  protected Object clone() throws CloneNotSupportedException {
    // First, perform a shallow copy.
    CloneDemo4 temp = (CloneDemo4) super.clone();
    if (a != null)
      temp.a = new A();
    return temp;
  }
}





Uses serialization to perform deep copy cloning.

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Main implements Cloneable, Serializable {
  public Object clone() {
    Object clonedObj = null;
    try {
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream(baos);
      oos.writeObject(this);
      oos.close();
      ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
      ObjectInputStream ois = new ObjectInputStream(bais);
      clonedObj = ois.readObject();
      ois.close();
    } catch (Exception cnfe) {
      System.out.println("Class not found " + cnfe);
    }
    return clonedObj;
  }
}