Skip to content

Instantly share code, notes, and snippets.

@wuyexiong
Created September 12, 2013 04:14
Show Gist options
  • Save wuyexiong/6532988 to your computer and use it in GitHub Desktop.
Save wuyexiong/6532988 to your computer and use it in GitHub Desktop.
Java 浅拷贝深拷贝,以及深拷贝优化。我草,碉堡了。
package deepcopy;
import java.util.Vector;
public class CloneExample1 {
public static void main(String[] args) {
// Make a Vector
Vector original = new Vector();
// Make a StringBuffer and add it to the Vector
StringBuffer text = new StringBuffer("The quick brown fox");
original.addElement(text);
// Clone the vector and print out the contents
Vector clone = (Vector) original.clone();
System.out.println("A. After cloning");
printVectorContents(original, "original");
printVectorContents(clone, "clone");
System.out.println(
"--------------------------------------------------------");
System.out.println();
// Add another object (an Integer) to the clone and
// print out the contents
clone.addElement(new Integer(5));
System.out.println("B. After adding an Integer to the clone");
printVectorContents(original, "original");
printVectorContents(clone, "clone");
System.out.println(
"--------------------------------------------------------");
System.out.println();
// Change the StringBuffer contents
text.append(" jumps over the lazy dog.");
System.out.println("C. After modifying one of original's elements");
printVectorContents(original, "original");
printVectorContents(clone, "clone");
System.out.println(
"--------------------------------------------------------");
System.out.println();
}
public static void printVectorContents(Vector v, String name) {
System.out.println(" Contents of \"" + name + "\":");
// For each element in the vector, print out the index, the
// class of the element, and the element itself
for (int i = 0; i < v.size(); i++) {
Object element = v.elementAt(i);
System.out.println(" " + i + " (" +
element.getClass().getName() + "): " +
element);
}
System.out.println();
}
}
package deepcopy;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* Utility for making deep copies (vs. clone()'s shallow copies) of
* objects. Objects are first serialized and then deserialized. Error
* checking is fairly minimal in this implementation. If an object is
* encountered that cannot be serialized (or that references an object
* that cannot be serialized) an error is printed to System.err and
* null is returned. Depending on your specific application, it might
* make more sense to have copy(...) re-throw the exception.
*/
public class DeepCopy {
/**
* Returns a copy of the object, or null if the object cannot
* be serialized.
*/
public static Object copy(Object orig) {
Object obj = null;
try {
// Write the object out to a byte array
FastByteArrayOutputStream fbos =
new FastByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(fbos);
out.writeObject(orig);
out.flush();
out.close();
// Retrieve an input stream from the byte array and read
// a copy of the object back in.
ObjectInputStream in =
new ObjectInputStream(fbos.getInputStream());
obj = in.readObject();
}
catch(IOException e) {
e.printStackTrace();
}
catch(ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
return obj;
}
}
package deepcopy;
import java.io.InputStream;
/**
* ByteArrayInputStream implementation that does not synchronize methods.
*/
public class FastByteArrayInputStream extends InputStream {
/**
* Our byte buffer
*/
protected byte[] buf = null;
/**
* Number of bytes that we can read from the buffer
*/
protected int count = 0;
/**
* Number of bytes that have been read from the buffer
*/
protected int pos = 0;
public FastByteArrayInputStream(byte[] buf, int count) {
this.buf = buf;
this.count = count;
}
public final int available() {
return count - pos;
}
public final int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
public final int read(byte[] b, int off, int len) {
if (pos >= count)
return -1;
if ((pos + len) > count)
len = (count - pos);
System.arraycopy(buf, pos, b, off, len);
pos += len;
return len;
}
public final long skip(long n) {
if ((pos + n) > count)
n = count - pos;
if (n < 0)
return 0;
pos += n;
return n;
}
}
package deepcopy;
import java.io.InputStream;
import java.io.OutputStream;
/**
* ByteArrayOutputStream implementation that doesn't synchronize methods
* and doesn't copy the data on toByteArray().
*/
public class FastByteArrayOutputStream extends OutputStream {
/**
* Buffer and size
*/
protected byte[] buf = null;
protected int size = 0;
/**
* Constructs a stream with buffer capacity size 5K
*/
public FastByteArrayOutputStream() {
this(5 * 1024);
}
/**
* Constructs a stream with the given initial size
*/
public FastByteArrayOutputStream(int initSize) {
this.size = 0;
this.buf = new byte[initSize];
}
/**
* Ensures that we have a large enough buffer for the given size.
*/
private void verifyBufferSize(int sz) {
if (sz > buf.length) {
byte[] old = buf;
buf = new byte[Math.max(sz, 2 * buf.length )];
System.arraycopy(old, 0, buf, 0, old.length);
old = null;
}
}
public int getSize() {
return size;
}
/**
* Returns the byte array containing the written data. Note that this
* array will almost always be larger than the amount of data actually
* written.
*/
public byte[] getByteArray() {
return buf;
}
public final void write(byte b[]) {
verifyBufferSize(size + b.length);
System.arraycopy(b, 0, buf, size, b.length);
size += b.length;
}
public final void write(byte b[], int off, int len) {
verifyBufferSize(size + len);
System.arraycopy(b, off, buf, size, len);
size += len;
}
public final void write(int b) {
verifyBufferSize(size + 1);
buf[size++] = (byte) b;
}
public void reset() {
size = 0;
}
/**
* Returns a ByteArrayInputStream for reading back the written data
*/
public InputStream getInputStream() {
return new FastByteArrayInputStream(buf, size);
}
}
package deepcopy;
import java.util.Hashtable;
import java.util.Vector;
import java.util.Date;
public class SpeedTest {
public static void main(String[] args) {
// Make a reasonable large test object. Note that this doesn't
// do anything useful -- it is simply intended to be large, have
// several levels of references, and be somewhat random. We start
// with a hashtable and add vectors to it, where each element in
// the vector is a Date object (initialized to the current time),
// a semi-random string, and a (circular) reference back to the
// object itself. In this case the resulting object produces
// a serialized representation that is approximate 700K.
Hashtable obj = new Hashtable();
for (int i = 0; i < 100; i++) {
Vector v = new Vector();
for (int j = 0; j < 100; j++) {
v.addElement(new Object[] {
new Date(),
"A random number: " + Math.random(),
obj
});
}
obj.put(new Integer(i), v);
}
int iterations = 10;
// Make copies of the object using the unoptimized version
// of the deep copy utility.
long unoptimizedTime = 0L;
for (int i = 0; i < iterations; i++) {
long start = System.currentTimeMillis();
Object copy = UnoptimizedDeepCopy.copy(obj);
unoptimizedTime += (System.currentTimeMillis() - start);
// Avoid having GC run while we are timing...
copy = null;
System.gc();
}
// Repeat with the optimized version
long optimizedTime = 0L;
for (int i = 0; i < iterations; i++) {
long start = System.currentTimeMillis();
Object copy = DeepCopy.copy(obj);
optimizedTime += (System.currentTimeMillis() - start);
// Avoid having GC run while we are timing...
copy = null;
System.gc();
}
System.out.println("Unoptimized time: " + unoptimizedTime);
System.out.println(" Optimized time: " + optimizedTime);
}
}
package deepcopy;
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
/**
* Utility for making deep copies (vs. clone()'s shallow copies) of
* objects. Objects are first serialized and then deserialized. Error
* checking is fairly minimal in this implementation. If an object is
* encountered that cannot be serialized (or that references an object
* that cannot be serialized) an error is printed to System.err and
* null is returned. Depending on your specific application, it might
* make more sense to have copy(...) re-throw the exception.
*
* A later version of this class includes some minor optimizations.
*/
public class UnoptimizedDeepCopy {
/**
* Returns a copy of the object, or null if the object cannot
* be serialized.
*/
public static Object copy(Object orig) {
Object obj = null;
try {
// Write the object out to a byte array
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bos);
out.writeObject(orig);
out.flush();
out.close();
// Make an input stream from the byte array and read
// a copy of the object back in.
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(bos.toByteArray()));
obj = in.readObject();
}
catch(IOException e) {
e.printStackTrace();
}
catch(ClassNotFoundException cnfe) {
cnfe.printStackTrace();
}
return obj;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment