Java/Class/Clone
Содержание
- 1 A Cloning Example
- 2 A collection of utilities to workaround limitations of Java clone framework
- 3 Arrays are automatically cloneable
- 4 Checking to see if a reference can be cloned
- 5 Class is declared to be cloneable.
- 6 Clone an object with clone method from parent
- 7 Clone demo
- 8 Clone objects
- 9 Clone Via Serialization
- 10 Cloning a composed object
- 11 Creating a Deep Copy
- 12 Creating local copies with clone
- 13 Deep clone Object
- 14 Deep clone serializing/de-serializng Clone
- 15 Deep Copy Test
- 16 Demonstration of cloning
- 17 Go through a few gyrations to add cloning to your own class
- 18 Implements a pool of internalized objects
- 19 Manipulate properties after clone operation
- 20 Serializable and clone
- 21 Serializable Clone
- 22 Shallow Copy Test
- 23 Simple demo of avoiding side-effects by using Object.clone
- 24 Tests cloning to see if destination of references are also cloned
- 25 The clone operation works for only a few items in the standard Java library
- 26 Uses serialization to perform deep copy cloning.
- 27 Utility for object cloning
- 28 You can insert Cloneability at any level of inheritance
A Cloning Example
<source lang="java">
public class MainClass {
public static void main(String[] args) { Employee emp1 = new Employee("M", "A"); emp1.setSalary(40000.0); Employee emp2 = (Employee) emp1.clone(); emp1.setLastName("Smith"); System.out.println(emp1); System.out.println(emp2); }
} class Employee {
private String lastName; private String firstName; private Double salary; public Employee(String lastName, String firstName) { this.lastName = lastName; this.firstName = firstName; } public String getLastName() { return this.lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getFirstName() { return this.firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public Double getSalary() { return this.salary; } public void setSalary(Double salary) { this.salary = salary; } public Object clone() { Employee emp; emp = new Employee(this.lastName, this.firstName); emp.setSalary(this.salary); return emp; } public String toString() { return this.getClass().getName() + "[" + this.firstName + " " + this.lastName + ", " + this.salary + "]"; }
}
</source>
A collection of utilities to workaround limitations of Java clone framework
<source lang="java">
/*
* $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() { }
}
</source>
Arrays are automatically cloneable
<source lang="java">
public class Main {
public static void main(String[] argv) throws Exception { int[] ints = new int[] { 123, 234 }; int[] intsClone = (int[]) ints.clone(); }
}
</source>
Checking to see if a reference can be cloned
<source lang="java">
// : appendixa:CheckCloneable.java // Checking to see if a reference can be cloned. // From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002 // www.BruceEckel.ru. See copyright notice in CopyRight.txt. // Can"t clone this because it doesn"t override clone(): class Ordinary { } // Overrides clone, but doesn"t implement Cloneable: class WrongClone extends Ordinary {
public Object clone() throws CloneNotSupportedException { return super.clone(); // Throws exception }
} // Does all the right things for cloning: class IsCloneable extends Ordinary implements Cloneable {
public Object clone() throws CloneNotSupportedException { return super.clone(); }
} // Turn off cloning by throwing the exception: class NoMore extends IsCloneable {
public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); }
} class TryMore extends NoMore {
public Object clone() throws CloneNotSupportedException { // Calls NoMore.clone(), throws exception: return super.clone(); }
} class BackOn extends NoMore {
private BackOn duplicate(BackOn b) { // Somehow make a copy of b and return that copy. // This is a dummy copy, just to make the point: return new BackOn(); } public Object clone() { // Doesn"t call NoMore.clone(): return duplicate(this); }
} // You can"t inherit from this, so you can"t override // the clone method as you can in BackOn: final class ReallyNoMore extends NoMore { } public class CheckCloneable {
public static Ordinary tryToClone(Ordinary ord) { String id = ord.getClass().getName(); System.out.println("Attempting " + id); Ordinary x = null; if (ord instanceof Cloneable) { try { x = (Ordinary) ((IsCloneable) ord).clone(); System.out.println("Cloned " + id); } catch (CloneNotSupportedException e) { System.err.println("Could not clone " + id); } } else { System.out.println("Doesn"t implement Cloneable"); } return x; } public static void main(String[] args) { // Upcasting: Ordinary[] ord = { new IsCloneable(), new WrongClone(), new NoMore(), new TryMore(), new BackOn(), new ReallyNoMore(), }; Ordinary x = new Ordinary(); // This won"t compile; clone() is protected in Object: //! x = (Ordinary)x.clone(); // Checks first to see if a class implements Cloneable: for (int i = 0; i < ord.length; i++) tryToClone(ord[i]); }
} ///:~
</source>
Class is declared to be cloneable.
<source lang="java">
class Employee implements Cloneable {
String name; int salary; public Employee(String name, int salary) { this.name = name; this.salary = salary; } public Employee() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public void setSalary(int salary) { this.salary = salary; } public int getSalary() { return this.salary; } public Object clone() throws CloneNotSupportedException { try { return super.clone(); } catch (CloneNotSupportedException cnse) { System.out.println("CloneNotSupportedException thrown " + cnse); throw new CloneNotSupportedException(); } }
} 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()); } catch (CloneNotSupportedException cnse) { System.out.println("Clone not supported"); } }
}
</source>
Clone an object with clone method from parent
<source lang="java">
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; }
}
</source>
Clone demo
<source lang="java">
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002. * All rights reserved. Software written by Ian F. Darwin and others. * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s, * pioneering role in inventing and promulgating (and standardizing) the Java * language and environment is gratefully acknowledged. * * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for * inventing predecessor languages C and C++ is also gratefully acknowledged. */
class One extends java.lang.Object {
int x;
} class Two extends One /*implements Cloneable*/ {
int y; public void foo() { try { Object o = this.clone(); } catch (CloneNotSupportedException ex) { System.err.println(ex); } } public Object clone() throws CloneNotSupportedException { return super.clone(); }
} public class CloneSub {
public static void main(String[] args) throws CloneNotSupportedException { Two t1 = new Two(); t1.x = 100; t1.y = 200; Two t2 = (Two)t1.clone(); System.out.println(t2); System.out.println(t2.y); }
}
</source>
Clone objects
<source lang="java">
public class Main {
public static void main(String[] args) { Person person1 = new Person(); person1.setFirstName("F"); person1.setLastName("L"); Person person2 = (Person) person1.clone(); Person person3 = (Person) person2.clone(); System.out.println("Person 1: " + person1.getFirstName() + " " + person1.getLastName()); System.out.println("Person 2: " + person2.getFirstName() + " " + person2.getLastName()); System.out.println("Person 3: " + person3.getFirstName() + " " + person3.getLastName()); }
} class Person implements Cloneable {
private String firstName; private String lastName; public Object clone() { Person obj = new Person(); obj.setFirstName(this.firstName); obj.setLastName(this.lastName); return obj; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; }
} /* Person 1: F L Person 2: F L Person 3: F L
- /
</source>
Clone Via Serialization
<source lang="java">
/**
* * The ObjectStyle Group Software License, version 1.1 * ObjectStyle Group - http://objectstyle.org/ * * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors * of the software. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if any, * must include the following acknowlegement: * "This product includes software developed by independent contributors * and hosted on ObjectStyle Group web site (http://objectstyle.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse * or promote products derived from this software without prior written * permission. For written permission, email * "andrus at objectstyle dot org". * * 5. Products derived from this software may not be called "ObjectStyle" * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their * names without prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS"" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * * This software consists of voluntary contributions made by many * individuals and hosted on ObjectStyle Group web site. For more * information on the ObjectStyle Group, please see * <http://objectstyle.org/>. */
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.Serializable; import java.lang.reflect.Member; import java.lang.reflect.Modifier; import java.net.URL; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.ruparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException; import org.xml.sax.XMLReader; /**
* Contains various unorganized static utility methods used across Cayenne. * * @author Andrei Adamchik */
public class Util {
/** * Creates Serializable object copy using serialization/deserialization. */ public static Object cloneViaSerialization(Serializable obj) throws Exception { ByteArrayOutputStream bytes = new ByteArrayOutputStream() { public synchronized byte[] toByteArray() { return buf; } }; ObjectOutputStream out = new ObjectOutputStream(bytes); out.writeObject(obj); out.close(); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes .toByteArray())); Object objCopy = in.readObject(); // no need to close the stream - we created it and now will be throwing away... // in.close(); return objCopy; }
}
</source>
Cloning a composed object
<source lang="java">
// : appendixa:DeepCopy.java // Cloning a composed object. // {Depends: junit.jar} // From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002 // www.BruceEckel.ru. See copyright notice in CopyRight.txt. import junit.framework.*; class DepthReading implements Cloneable {
private double depth; public DepthReading(double depth) { this.depth = depth; } public Object clone() { Object o = null; try { o = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } public double getDepth() { return depth; } public void setDepth(double depth) { this.depth = depth; } public String toString() { return String.valueOf(depth); }
} class TemperatureReading implements Cloneable {
private long time; private double temperature; public TemperatureReading(double temperature) { time = System.currentTimeMillis(); this.temperature = temperature; } public Object clone() { Object o = null; try { o = super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } return o; } public double getTemperature() { return temperature; } public void setTemperature(double temperature) { this.temperature = temperature; } public String toString() { return String.valueOf(temperature); }
} class OceanReading implements Cloneable {
private DepthReading depth; private TemperatureReading temperature; public OceanReading(double tdata, double ddata) { temperature = new TemperatureReading(tdata); depth = new DepthReading(ddata); } public Object clone() { OceanReading o = null; try { o = (OceanReading) super.clone(); } catch (CloneNotSupportedException e) { e.printStackTrace(); } // Must clone references: o.depth = (DepthReading) o.depth.clone(); o.temperature = (TemperatureReading) o.temperature.clone(); return o; // Upcasts back to Object } public TemperatureReading getTemperatureReading() { return temperature; } public void setTemperatureReading(TemperatureReading tr) { temperature = tr; } public DepthReading getDepthReading() { return depth; } public void setDepthReading(DepthReading dr) { this.depth = dr; } public String toString() { return "temperature: " + temperature + ", depth: " + depth; }
} public class DeepCopy extends TestCase {
public DeepCopy(String name) { super(name); } public void testClone() { OceanReading reading = new OceanReading(33.9, 100.5); // Now clone it: OceanReading clone = (OceanReading) reading.clone(); TemperatureReading tr = clone.getTemperatureReading(); tr.setTemperature(tr.getTemperature() + 1); clone.setTemperatureReading(tr); DepthReading dr = clone.getDepthReading(); dr.setDepth(dr.getDepth() + 1); clone.setDepthReading(dr); assertEquals(reading.toString(), "temperature: 33.9, depth: 100.5"); assertEquals(clone.toString(), "temperature: 34.9, depth: 101.5"); } public static void main(String[] args) { junit.textui.TestRunner.run(DeepCopy.class); }
} ///:~
</source>
Creating a Deep Copy
<source lang="java">
public class MainClass {
public static void main(String[] args) { Employee emp1 = new Employee("M", "A"); emp1.setSalary(40000.0); emp1.address = new Address("First Street", "San F", "CA", "93702"); Employee emp2 = (Employee) emp1.clone(); printEmployee(emp1); printEmployee(emp2); emp2.setLastName("Smith"); emp2.address = new Address("Street", "B", "CA", "93722"); printEmployee(emp1); printEmployee(emp2); } private static void printEmployee(Employee e) { System.out.println(e.getFirstName() + " " + e.getLastName()); System.out.println(e.address.getAddress()); System.out.println("Salary: " + e.getSalary()); }
} class Employee implements Cloneable {
private String lastName; private String firstName; private Double salary; public Address address; public Employee(String lastName, String firstName) { this.lastName = lastName; this.firstName = firstName; this.address = new Address(); } public String getLastName() { return this.lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getFirstName() { return this.firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public Double getSalary() { return this.salary; } public void setSalary(Double salary) { this.salary = salary; } public Object clone() { Employee emp; try { emp = (Employee) super.clone(); emp.address = (Address) address.clone(); } catch (CloneNotSupportedException e) { return null; // will never happen } return emp; } public String toString() { return this.getClass().getName() + "[" + this.firstName + " " + this.lastName + ", " + this.salary + "]"; }
} class Address implements Cloneable {
private String street; private String city; private String state; private String zipCode; public Address() { this.street = ""; this.city = ""; this.state = ""; this.zipCode = ""; } public Address(String street, String city, String state, String zipCode) { this.street = street; this.city = city; this.state = state; this.zipCode = zipCode; } public Object clone(){ try { return super.clone(); } catch (CloneNotSupportedException e) { return null; // will never happen } } public String getAddress() { return this.street + "\n" + this.city + ", " + this.state + " " + this.zipCode; }
}
</source>
Creating local copies with clone
<source lang="java">
// : appendixa:LocalCopy.java // Creating local copies with clone(). // From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002 // www.BruceEckel.ru. See copyright notice in CopyRight.txt.
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 {
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); }
} ///:~
</source>
Deep clone Object
<source lang="java">
/*
* 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); } } }
}
</source>
Deep clone serializing/de-serializng Clone
<source lang="java">
/*
* 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 objToClone
*
* @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;
}
}
</source>
Deep Copy Test
<source lang="java">
/* Correct Output: Original (orginal values): Person-A - Civic Clone (before change): Person-A - Civic Clone (after change): Person-B - Accord Original (after clone is modified): Person-A - Civic
- /
/* Software Architecture Design Patterns in Java by Partha Kuchana Auerbach Publications
- /
class Person implements Cloneable {
//Lower-level object private Car car; private String name; public Car getCar() { return car; } public String getName() { return name; } public void setName(String s) { name = s; } public Person(String s, String t) { name = s; car = new Car(t); } public Object clone() { //Deep copy Person p = new Person(name, car.getName()); return p; }
} class Car {
private String name; public String getName() { return name; } public void setName(String s) { name = s; } public Car(String s) { name = s; }
} public class DeepCopyTest {
public static void main(String[] args) { //Original Object Person p = new Person("Person-A", "Civic"); System.out.println("Original (orginal values): " + p.getName() + " - " + p.getCar().getName()); //Clone as a shallow copy Person q = (Person) p.clone(); System.out.println("Clone (before change): " + q.getName() + " - " + q.getCar().getName()); //change the primitive member q.setName("Person-B"); //change the lower-level object q.getCar().setName("Accord"); System.out.println("Clone (after change): " + q.getName() + " - " + q.getCar().getName()); System.out.println("Original (after clone is modified): " + p.getName() + " - " + p.getCar().getName()); }
}
</source>
Demonstration of cloning
<source lang="java">
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002. * All rights reserved. Software written by Ian F. Darwin and others. * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s, * pioneering role in inventing and promulgating (and standardizing) the Java * language and environment is gratefully acknowledged. * * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for * inventing predecessor languages C and C++ is also gratefully acknowledged. */
/** Demonstration of cloning. */ public class Clone1 implements Cloneable {
/** Clone this object. Call super.clone() to do the work */ public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException ex) { System.out.println("Now that"s a surprise!!"); throw new InternalError(ex.toString()); } } int x; transient int y; // will be cloned, but not serialized /** Display the current object as a string */ public String toString() { return "Clone1[" + x + "," + y + "]"; }
}
</source>
Go through a few gyrations to add cloning to your own class
<source lang="java">
// : appendixa:AddingClone.java // You must go through a few gyrations // to add cloning to your own class. // From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002 // www.BruceEckel.ru. See copyright notice in CopyRight.txt. import java.util.ArrayList; import java.util.Iterator; 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.err.println("Int2 can"t clone"); } return o; }
} // Inheritance doesn"t remove cloneability: class Int3 extends Int2 {
private int j; // Automatically duplicated 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(); ArrayList v = new ArrayList(); for (int i = 0; i < 10; i++) v.add(new Int2(i)); System.out.println("v: " + v); ArrayList v2 = (ArrayList) v.clone(); // Now clone each element: for (int i = 0; i < v.size(); i++) v2.set(i, ((Int2) v2.get(i)).clone()); // Increment all v2"s elements: for (Iterator e = v2.iterator(); e.hasNext();) ((Int2) e.next()).increment(); System.out.println("v2: " + v2); // See if it changed v"s elements: System.out.println("v: " + v); }
} ///:~
</source>
Implements a pool of internalized objects
<source lang="java">
/*
* Copyright 2007 (C) TJDO. * All rights reserved. * * This software is distributed under the terms of the TJDO License version 1.0. * See the terms of the TJDO License in the documentation provided with this software. * * $Id: InternPool.java,v 1.1 2007/11/30 19:42:26 jackknifebarber Exp $ */
import java.lang.ref.Reference; import java.lang.ref.WeakReference; import java.util.AbstractCollection; import java.util.Collections; import java.util.Iterator; import java.util.Map; import java.util.WeakHashMap;
/**
* Implements a pool of internalized objects. * Used to implement pools that behave like the one used by String.intern().*
* This implementation is synchronized.
* It is a generic collection that is unmodifiable with the exception of the
* {@link #intern} method.
*
* @author
* @version $Revision: 1.1 $
*/
public class InternPool extends AbstractCollection
{
private final Map pool = new WeakHashMap();
/**
* Returns a canonical representation for the specified object.
* <p>
* This method behaves much like String.intern()
.
* A pool of objects, initially empty, is maintained privately.
* <p>
* If the pool already contains an object equal to the specified object as
* determined by the equals(Object)
method, then the object
* from the pool is returned.
* Otherwise, the specified object is added to the pool and a reference to
* the specified object is returned.
* <p>
* It follows that for any two objects o1
and o2
,
* intern(o1) == intern(o2)
is true
* if and only if o1.equals(o2)
is true
.
*
* @param candidate
* the object to internalize
*
* @return
* an object that is equivalent to the specified object, but is
* guaranteed to be from a pool of unique objects.
*/
public synchronized Object intern(Object candidate)
{
Reference ref = (Reference)pool.get(candidate);
Object pooled = ref == null ? null : ref.get();
if (pooled == null)
{
pooled = candidate;
pool.put(pooled, new WeakReference(pooled));
}
return pooled;
}
public synchronized boolean contains(Object o)
{
return pool.containsKey(o);
}
public synchronized Iterator iterator()
{
return Collections.unmodifiableSet(pool.keySet()).iterator();
}
public synchronized int size()
{
return pool.size();
}
}
</source>
Manipulate properties after clone operation
<source lang="java">
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; }
}
</source>
Serializable and clone
<source lang="java">
// : appendixa:Compete.java // From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002 // www.BruceEckel.ru. See copyright notice in CopyRight.txt. import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; class Thing1 implements Serializable { } class Thing2 implements Serializable {
Thing1 o1 = new Thing1();
} class Thing3 implements Cloneable {
public Object clone() { Object o = null; try { o = super.clone(); } catch (CloneNotSupportedException e) { System.err.println("Thing3 can"t clone"); } return o; }
} class Thing4 implements Cloneable {
private Thing3 o3 = new Thing3(); public Object clone() { Thing4 o = null; try { o = (Thing4) super.clone(); } catch (CloneNotSupportedException e) { System.err.println("Thing4 can"t clone"); } // Clone the field, too: o.o3 = (Thing3) o3.clone(); return o; }
} public class Compete {
public static final int SIZE = 25000; public static void main(String[] args) throws Exception { Thing2[] a = new Thing2[SIZE]; for (int i = 0; i < a.length; i++) a[i] = new Thing2(); Thing4[] b = new Thing4[SIZE]; for (int i = 0; i < b.length; i++) b[i] = new Thing4(); long t1 = System.currentTimeMillis(); ByteArrayOutputStream buf = new ByteArrayOutputStream(); ObjectOutputStream o = new ObjectOutputStream(buf); for (int i = 0; i < a.length; i++) o.writeObject(a[i]); // Now get copies: ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream( buf.toByteArray())); Thing2[] c = new Thing2[SIZE]; for (int i = 0; i < c.length; i++) c[i] = (Thing2) in.readObject(); long t2 = System.currentTimeMillis(); System.out.println("Duplication via serialization: " + (t2 - t1) + " Milliseconds"); // Now try cloning: t1 = System.currentTimeMillis(); Thing4[] d = new Thing4[SIZE]; for (int i = 0; i < d.length; i++) d[i] = (Thing4) b[i].clone(); t2 = System.currentTimeMillis(); System.out.println("Duplication via cloning: " + (t2 - t1) + " Milliseconds"); }
} ///:~
</source>
Serializable Clone
<source lang="java">
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(); }
}
</source>
Shallow Copy Test
<source lang="java">
/* Software Architecture Design Patterns in Java by Partha Kuchana Auerbach Publications
- /
class Person implements Cloneable {
//Lower-level object private Car car; private String name; public Car getCar() { return car; } public String getName() { return name; } public void setName(String s) { name = s; } public Person(String s, String t) { name = s; car = new Car(t); } public Object clone() { //shallow copy try { return super.clone(); } catch (CloneNotSupportedException e) { return null; } }
} class Car {
private String name; public String getName() { return name; } public void setName(String s) { name = s; } public Car(String s) { name = s; }
} public class ShallowCopyTest {
public static void main(String[] args) { //Original Object Person p = new Person("Person-A", "Civic"); System.out.println("Original (orginal values): " + p.getName() + " - " + p.getCar().getName()); //Clone as a shallow copy Person q = (Person) p.clone(); System.out.println("Clone (before change): " + q.getName() + " - " + q.getCar().getName()); //change the primitive member q.setName("Person-B"); //change the lower-level object q.getCar().setName("Accord"); System.out.println("Clone (after change): " + q.getName() + " - " + q.getCar().getName()); System.out.println("Original (after clone is modified): " + p.getName() + " - " + p.getCar().getName()); }
}
</source>
Simple demo of avoiding side-effects by using Object.clone
<source lang="java">
/*
* Copyright (c) Ian F. Darwin, http://www.darwinsys.ru/, 1996-2002. * All rights reserved. Software written by Ian F. Darwin and others. * $Id: LICENSE,v 1.8 2004/02/09 03:33:38 ian Exp $ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS"" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Java, the Duke mascot, and all variants of Sun"s Java "steaming coffee * cup" logo are trademarks of Sun Microsystems. Sun"s, and James Gosling"s, * pioneering role in inventing and promulgating (and standardizing) the Java * language and environment is gratefully acknowledged. * * The pioneering role of Dennis Ritchie and Bjarne Stroustrup, of AT&T, for * inventing predecessor languages C and C++ is also gratefully acknowledged. */
import java.util.*; /**
* Simple demo of avoiding side-effects by using Object.clone() * to duplicate an object before passing it to your enemy"s methods. * Cloneable is a "marker" interface: it has no methods, but is tested * for by Object.clone. If you implement it, you tell Object.clone that * your data is stable enough that field-by-field copy is OK. */
class Enemy {
public void munge(SideEffects md) { System.out.println("Object is " + md); md.year = 0; md.td.setYear(71); // Ignore deprecation warnings }
} public class SideEffects implements Cloneable {
/** When we clone a "SideEffects", this REFERENCE gets cloned */ public Date td; /** When we clone a "SideEffects", this integer does NOT get cloned */ volatile int year; public static void main(String[] argv) throws CloneNotSupportedException { new SideEffects().process(); } SideEffects() { td = new Date(); // today year = td.getYear(); } public void process() throws CloneNotSupportedException { Enemy r = new Enemy(); System.out.println("We have seen the enemy, and he is " + r); System.out.println("Today is " + td + "; nice weather, isn"t it?"); System.out.println("And the year is " + year); r.munge((SideEffects)this.clone()); System.out.println("Why, I believe it is now " + td); if (year == 0) // should not happen!! System.out.println("** PANIC IN YEAR ZERO **"); System.out.println("But wait, the year is still " + year); r.munge(this); System.out.println("Now I"m certain that it"s " + td); System.out.println("Now the year is " + year); }
}
</source>
Tests cloning to see if destination of references are also cloned
<source lang="java">
// : appendixa:Snake.java // Tests cloning to see if destination // of references are also cloned. // From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002 // www.BruceEckel.ru. See copyright notice in CopyRight.txt. public class Snake implements Cloneable {
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); }
} ///:~
</source>
The clone operation works for only a few items in the standard Java library
<source lang="java">
// : appendixa:Cloning.java // The clone() operation works for only a few // items in the standard Java library. // From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002 // www.BruceEckel.ru. See copyright notice in CopyRight.txt. import java.util.ArrayList; import java.util.Iterator; class Int {
private int i; public Int(int ii) { i = ii; } public void increment() { i++; } public String toString() { return Integer.toString(i); }
} public class Cloning {
public static void main(String[] args) { ArrayList v = new ArrayList(); for (int i = 0; i < 10; i++) v.add(new Int(i)); System.out.println("v: " + v); ArrayList v2 = (ArrayList) v.clone(); // Increment all v2"s elements: for (Iterator e = v2.iterator(); e.hasNext();) ((Int) e.next()).increment(); // See if it changed v"s elements: System.out.println("v: " + v); }
} ///:~
</source>
Uses serialization to perform deep copy cloning.
<source lang="java">
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; }
}
</source>
Utility for object cloning
<source lang="java">
/*
* 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 objToClone
*
* @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;
}
}
</source>
You can insert Cloneability at any level of inheritance
<source lang="java">
// : appendixa:HorrorFlick.java // You can insert Cloneability at any level of inheritance. // From "Thinking in Java, 3rd ed." (c) Bruce Eckel 2002 // www.BruceEckel.ru. See copyright notice in CopyRight.txt.
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 RuntimeException(e); } }
} 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(); }
} ///:~
</source>