Java List 的深拷贝

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

/*
 * 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("复制前:");
        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;
    }
}

运行结果如下:

run:
复制前:
[email protected] 1.1
[email protected] 1.2
[email protected] 1.3
构造函数复制且修改后,新的lst2:
[email protected] 2.1
[email protected] 1.2
[email protected] 1.3
构造函数复制且修改后,原始lst:
[email protected] 2.1
[email protected] 1.2
[email protected] 1.3
对象序列化复制且修改后,新的lst3:
[email protected] 3.1
[email protected] 1.2
[email protected] 1.3
对象序列化复制且修改后,原始lst:
[email protected] 2.1
[email protected] 1.2
[email protected] 1.3
对象序列化复制且修改后,新的lst4:
[email protected] 4.1
[email protected] 1.2
[email protected] 1.3
对象序列化复制且修改后,原始lst:
[email protected] 2.1
[email protected] 1.2
[email protected] 1.3

可以看到,用构造函数(旧List)的方法,是浅拷贝,拷贝的只是List中的元素,即引用,而不是这些元素或引用指向的值。

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

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

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

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

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

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

时间: 2024-10-22 10:46:36

Java List 的深拷贝的相关文章

Java中的深拷贝和浅拷贝 原型模式

1: Java中浅拷贝和深拷贝的定义:      浅拷贝:就是指两个对象共同拥有同一个值,一个对象改变了该值,也会影响到另一个对象.      深拷贝:就是两个对象的值相等,但是互相独立. (深拷贝才是真正的拷贝,浅拷贝只是将引用指向了同一份对象) 2:Java中几种常见的拷贝操作: (1)"="操作:也就是赋值操作: (2)拷贝构造函数:拷贝构造函数就是构造函数的参数的类型是该构造函数所在的类,即参数就是该类的一个对象. <span style="font-size:

浅谈Java中的深拷贝和浅拷贝

浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: [java] view plaincopyprint? int apples = 5; int pears = apples; int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float

Java 浅拷贝,深拷贝

从Java 强引用,软引用,弱引用http://blog.csdn.net/jltxgcy/article/details/35558465一文中,我们看到把一个对象赋值给另一个对象,本质上是增加了引用计数,但是它们都指向同样的堆内存,它们是一个对象.如果我们想要一个独立的对象,改怎么办呢?答案是clone. 1.浅拷贝 浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象. ShallowCopy.java class Professor0 imple

Java 浅拷贝和深拷贝

一看就懂的,java深拷贝浅拷贝 将一个对象的引用复制给另外一个对象,一共有三种方式.第一种方式是直接赋值,第二种方式是浅拷贝,第三种是深拷贝.所以大家知道了哈,这三种概念实际上都是为了拷贝对象啊. 1.直接赋值 好,下面我们先看第一种方式,直接赋值.在Java中,A a1 = a2,我们需要理解的是这实际上复制的是引用,也就是说a1和a2指向的是同一个对象.因此,当a1变化的时候,a2里面的成员变量也会跟着变化.各位,请看下面的代码吧! /* 建立类 */ class Resume { pri

java浅拷贝与深拷贝详解

/** * @author MaskedMen *java深克隆与浅克隆讲解 *技术交流群:JAVA/WEB/安卓精英群 316278345 *联系邮箱:[email protected] */ public class CloneDemo { public static void main(String[] args) { Person maskedmen1 = new Person("maskedmen1",20); Fruit watermelon = new Fruit(&qu

Java中的深拷贝(深复制)和浅拷贝(浅复制)

深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复制)和浅拷贝(浅复制),我们还是要给予足够的重视,因为有时这两个概念往往会给我们带来不小的困惑. 浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象.深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象.举例来说更加清楚:对象A1中包含对B1的引用

Java中的深拷贝和浅拷贝

1.浅拷贝与深拷贝概念 (1)浅拷贝(浅克隆) 浅拷贝又叫浅复制,将对象中的所有字段复制到新的对象(副本)中.其中,值类型字段(java中8中原始类型)的值被复制到副本中后,在副本中的修改不会影响到源对象对应的值.而引用类型的字段被复制到副本中的还是引用类型的引用,而不是引用的对象,在副本中对引用类型的字段值做修改会影响到源对象本身. 浅拷贝简单归纳就是只复制一个对象,对象内部存在指向其他对象,数组或引用则不复制. (2)深拷贝(深克隆) 将对象中的所有字段复制到新的对象中.不过,无论是对象的值

Java中的深拷贝和浅拷贝(转载)

深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽然java自动管理对象的回收,但对于深拷贝(深复制)和浅拷贝(浅复制),我们还是要给予足够的重视,因为有时这两个概念往往会给我们带来不小的困惑. 浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象.深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象.举例来说更加清楚:对象A1中包含对B1的引用

[clone]Java中的深拷贝和浅拷贝 实例解析

我们平时在开发中经常用到clone这个Object类的方法,但是super.clone()方法所返回的拷贝是浅拷贝,(所谓浅拷贝和深拷贝是相对的,浅拷贝中的内部对象与原始对象的内部对象是共享的,是同一个:而深拷贝中的内部对象也是不同的.),有些情况下,我们需要得到对象的深拷贝,如下面的情况 package day0815; import java.io.File; import java.util.Stack; import org.junit.Test; public class BaseTr