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
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 + "]";
}
}
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();
}
}
Checking to see if a reference can be cloned
// : 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]);
}
} ///:~
Class is declared to be cloneable.
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");
}
}
}
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;
}
}
Clone demo
/*
* 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);
}
}
Clone objects
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
*/
Clone Via Serialization
/**
*
* 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;
}
}
Cloning a composed object
// : 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);
}
} ///:~
Creating a Deep Copy
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;
}
}
Creating local copies with clone
// : 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);
}
} ///:~
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;
}
}
Deep Copy Test
/*
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());
}
}
Demonstration of cloning
/*
* 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 + "]";
}
}
Go through a few gyrations to add cloning to your own class
// : 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);
}
} ///:~
Implements a pool of internalized objects
/*
* 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 <dfn>internalized</dfn> objects.
* Used to implement pools that behave like the one used by String.intern().
* <p>
* 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 <code>String.intern()</code>.
* 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 <code>equals(Object)</code> 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 <code>o1</code> and <code>o2</code>,
* <code>intern(o1) == intern(o2)</code> is <code>true</code>
* if and only if <code>o1.equals(o2)</code> is <code>true</code>.
*
* @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();
}
}
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;
}
}
Serializable and clone
// : 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");
}
} ///:~
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 Test
/*
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());
}
}
Simple demo of avoiding side-effects by using Object.clone
/*
* 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);
}
}
Tests cloning to see if destination of references are also cloned
// : 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);
}
} ///:~
The clone operation works for only a few items in the standard Java library
// : 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);
}
} ///:~
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;
}
}
Utility for object cloning
/*
* 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;
}
}
You can insert Cloneability at any level of inheritance
// : 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();
}
} ///:~