Deep copy via serialization
When you consider Java’s object serialization (introduced in Chapter 12), you might observe that an object that’s serialized and then deserialized is, in effect, cloned.
So why not use serialization to perform deep copying? Here’s an example that compares the two approaches by timing them:
//: appendixa:Compete.java
import java.io.*;
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");
}
} ///:~
Thing2 and Thing4 contain member objects so that there’s some deep copying going on. It’s interesting to notice that while Serializable classes are easy to set up, there’s much more work going on to duplicate them. Cloning involves a lot of work to set up the class, but the actual duplication of objects is relatively simple. The results are interesting. Here is the output from three different runs:
Duplication via serialization: 547 Milliseconds
Duplication via cloning: 110 Milliseconds
Duplication via serialization: 547 Milliseconds
Duplication via cloning: 109 Milliseconds
Duplication via serialization: 547 Milliseconds
Duplication via cloning: 125 Milliseconds
In earlier versions of the JDK, the time required for serialization was much longer than that of cloning (roughly 15 times slower), and the serialization time tended to vary a lot. More recent versions of the JDK have sped up serialization and apparently made the time more consistent, as well. Here, it’s approximately four times slower, which brings it into the realm of reasonability for use as a cloning alternative.