Created
September 12, 2013 04:14
-
-
Save wuyexiong/6532988 to your computer and use it in GitHub Desktop.
Java 浅拷贝深拷贝,以及深拷贝优化。我草,碉堡了。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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