老是會遇到深拷貝與淺拷貝的問題,這里進行了一些測試。代碼例如以下:
</pre><pre name="code" class="java">/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.*;
/**
*
* @author User
*/
class Weiz implements Serializable{//對象序列化。要實現這個接口
private static final long serialVersionUID=123L;//序列化版本號
double x;
public Weiz(double a){
x=a;
}
}
public class test_copy {
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws IOException, ClassNotFoundException {
// TODO code application logic here
List<Weiz> lst=new ArrayList();
lst.add(new Weiz(1.1));
lst.add(new Weiz(1.2));
lst.add(new Weiz(1.3));
System.out.println("復制前。原始lst:");
for(int i=0;i<lst.size();++i){
System.out.println(lst.get(i)+" "+lst.get(i).x);
}
//System.out.println();
//構造函數復制 淺拷貝
List<Weiz> lst2=new ArrayList(lst);
//lst2.set(1, new Weiz(2.1));
lst2.get(0).x=2.1;
System.out.println("構造函數復制且改動后。新的lst2:");
for(int i=0;i<lst2.size();++i){
System.out.println(lst2.get(i)+" "+lst2.get(i).x);
}
System.out.println("構造函數復制且改動后,原始lst:");
for(int i=0;i<lst.size();++i){
System.out.println(lst.get(i)+" "+lst.get(i).x);
}
List<Weiz> lst3=deepCopy(lst);
lst3.get(0).x=3.1;
System.out.println("對象序列化復制且改動后,新的lst3:");
for(int i=0;i<lst3.size();++i){
System.out.println(lst3.get(i)+" "+lst3.get(i).x);
}
System.out.println("對象序列化復制且改動后,原始lst:");
for(int i=0;i<lst.size();++i){
System.out.println(lst.get(i)+" "+lst.get(i).x);
}
List<Weiz> lst4=deepCopy(lst);
lst4.get(0).x=4.1;
System.out.println("對象序列化復制且改動后。新的lst4:");
for(int i=0;i<lst4.size();++i){
System.out.println(lst4.get(i)+" "+lst4.get(i).x);
}
System.out.println("對象序列化復制且改動后。原始lst:");
for(int i=0;i<lst.size();++i){
System.out.println(lst.get(i)+" "+lst.get(i).x);
}
}
//關鍵代碼 運行序列化和反序列化 進行深度拷貝
public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
@SuppressWarnings("unchecked")
List<T> dest = (List<T>) in.readObject();
return dest;
}
//關鍵代碼 運行序列化和反序列化 進行深度拷貝,寫法不同而已,作用一樣
//個人習慣 怎么喜歡怎么來!
public List deepCopy2(List src) throws IOException, ClassNotFoundException{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(src);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in =new ObjectInputStream(byteIn);
List dest = (List)in.readObject();
return dest;
}
}
<pre name="code" class="plain">程序結果:
run: 復制前: readdxflunwen.Weiz@c17164 1.1 readdxflunwen.Weiz@1fb8ee3 1.2 readdxflunwen.Weiz@61de33 1.3 構造函數復制且改動后,新的lst2: readdxflunwen.Weiz@c17164 2.1 readdxflunwen.Weiz@1fb8ee3 1.2 readdxflunwen.Weiz@61de33 1.3 構造函數復制且改動后,原始lst: readdxflunwen.Weiz@c17164 2.1 readdxflunwen.Weiz@1fb8ee3 1.2 readdxflunwen.Weiz@61de33 1.3 對象序列化復制且改動后。新的lst3: readdxflunwen.Weiz@60aeb0 3.1 readdxflunwen.Weiz@16caf43 1.2 readdxflunwen.Weiz@66848c 1.3 對象序列化復制且改動后,原始lst: readdxflunwen.Weiz@c17164 2.1 readdxflunwen.Weiz@1fb8ee3 1.2 readdxflunwen.Weiz@61de33 1.3 對象序列化復制且改動后,新的lst4: readdxflunwen.Weiz@8813f2 4.1 readdxflunwen.Weiz@1d58aae 1.2 readdxflunwen.Weiz@83cc67 1.3 對象序列化復制且改動后。原始lst: readdxflunwen.Weiz@c17164 2.1 readdxflunwen.Weiz@1fb8ee3 1.2 readdxflunwen.Weiz@61de33 1.3 成功構建 (總時間: 4 秒)能夠看到。用構造函數(舊List)的方法。是淺拷貝,拷貝的僅僅是List中的元素,即引用,而不是這些元素或引用指向的值。
而通過對象序列化方法,則是深拷貝,是把這些引用指向的對象又一次創建了一份的。
從打印的結果也能夠看到。淺拷貝時,新list中元素的值和舊List是一樣,即引用是一樣的。而深拷貝時,新List中元素的值和舊List的是不一樣的。即引用值是不一樣的。你想一下。深拷貝是又一次創建了一份指向的對象。那么指向這個新對象的引用值當然和舊的應該是不一樣的!
對象序列化方法是參考別的文章。鏈接Here。
當類實現了Serializable 接口,它的對象才是可序列化的。
實際上,Serializable 是一個空接口,它的目的僅僅是標識一個類的對象能夠被序列化。
可序列化類中的屬性serialVersionUID用於標識類的序列化版本號,若不顯示定義該屬性,JVM會依據類的相關信息計算它的值,而類改動后的計算結果與改動前的計算結果往往不同,這樣反序列化時就會因版本號不兼容而失敗。
假設一個類是可序列化的。則它的全部子類也是可序列化的。當序列化對象時,假設對象的屬性又引用其它對象。則被引用的對象也必須是可序列化的。
