Java List 的深拷贝

来源:互联网 发布:zookeeper java 实例 编辑:程序博客网 时间:2024/06/05 04:02

老是会遇到深拷贝与浅拷贝的问题,这里进行了一些测试,代码如下:

</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.1readdxflunwen.Weiz@1fb8ee3 1.2readdxflunwen.Weiz@61de33 1.3构造函数复制且修改后,新的lst2:readdxflunwen.Weiz@c17164 2.1readdxflunwen.Weiz@1fb8ee3 1.2readdxflunwen.Weiz@61de33 1.3构造函数复制且修改后,原始lst:readdxflunwen.Weiz@c17164 2.1readdxflunwen.Weiz@1fb8ee3 1.2readdxflunwen.Weiz@61de33 1.3对象序列化复制且修改后,新的lst3:readdxflunwen.Weiz@60aeb0 3.1readdxflunwen.Weiz@16caf43 1.2readdxflunwen.Weiz@66848c 1.3对象序列化复制且修改后,原始lst:readdxflunwen.Weiz@c17164 2.1readdxflunwen.Weiz@1fb8ee3 1.2readdxflunwen.Weiz@61de33 1.3对象序列化复制且修改后,新的lst4:readdxflunwen.Weiz@8813f2 4.1readdxflunwen.Weiz@1d58aae 1.2readdxflunwen.Weiz@83cc67 1.3对象序列化复制且修改后,原始lst:readdxflunwen.Weiz@c17164 2.1readdxflunwen.Weiz@1fb8ee3 1.2readdxflunwen.Weiz@61de33 1.3成功构建 (总时间: 4 秒)
可以看到,用构造函数(旧List)的方法,是浅拷贝,拷贝的只是List中的元素,即引用,而不是这些元素或引用指向的值。

而通过对象序列化方法,则是深拷贝,是把这些引用指向的对象重新创建了一份的。

从打印的结果也可以看到,浅拷贝时,新list中元素的值和旧List是一样,即引用是一样的;而深拷贝时,新List中元素的值和旧List的是不一样的,即引用值是不一样的,你想一下,深拷贝是重新创建了一份指向的对象,那么指向这个新对象的引用值当然和旧的应该是不一样的!

对象序列化方法是参考别的文章,链接Here。

当类实现了Serializable 接口,它的对象才是可序列化的。实际上,Serializable 是一个空接口,它的目的只是标识一个类的对象可以被序列化。

可序列化类中的属性serialVersionUID用于标识类的序列化版本,若不显示定义该属性,JVM会根据类的相关信息计算它的值,而类修改后的计算结果与修改前的计算结果往往不同,这样反序列化时就会因版本不兼容而失败。

如果一个类是可序列化的,则它的所有子类也是可序列化的。当序列化对象时,如果对象的属性又引用其他对象,则被引用的对象也必须是可序列化的。

0 0
原创粉丝点击