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


    深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java。虽然java自动管理对象的回收,但对于深拷贝(深复制)和浅拷贝(浅复制),我们还是要给予足够的重视,因为有时这两个概念往往会给我们带来不小的困惑。

    浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。举例来说更加清楚:对象A1中包含对B1的引用,B1中包含对C1的引用。浅拷贝A1得到A2,A2 中依然包含对B1的引用,B1中依然包含对C1的引用。深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2 中包含对C2(C1的copy)的引用。

    若不对clone()方法进行改写,则调用此方法得到的对象即为浅拷贝,下面我们着重谈一下深拷贝。

    运行下面的程序,看一看浅拷贝:

     1 class Professor0 implements Cloneable {
     2     String name;
     3     int age;
     4  
     5     Professor0(String name, int age) {
     6         this.name = name;
     7         this.age = age;
     8     }
     9  
    10     public Object clone() throws CloneNotSupportedException {
    11         return super.clone();
    12     }
    13 }
    14  
    15 class Student0 implements Cloneable {
    16     String name;// 常量对象。
    17     int age;
    18     Professor0 p;// 学生1和学生2的引用值都是一样的。
    19  
    20     Student0(String name, int age, Professor0 p) {
    21         this.name = name;
    22         this.age = age;
    23         this.p = p;
    24     }
    25  
    26     public Object clone() {
    27         Student0 o = null;
    28         try {
    29             o = (Student0) super.clone();
    30         } catch (CloneNotSupportedException e) {
    31             System.out.println(e.toString());
    32         }
    33  
    34         return o;
    35     }
    36 }
    37  
    38 public class ShallowCopy {
    39     public static void main(String[] args) {
    40         Professor0 p = new Professor0("wangwu", 50);
    41         Student0 s1 = new Student0("zhangsan", 18, p);
    42         Student0 s2 = (Student0) s1.clone();
    43         s2.p.name = "lisi";
    44         s2.p.age = 30;
    45         s2.name = "z";
    46         s2.age = 45;
    47         System.out.println("学生s1的姓名:" + s1.name + "
    学生s1教授的姓名:" + s1.p.name + "," + "
    学生s1教授的年纪" + s1.p.age);// 学生1的教授
    48     }
    49 }

    s2变了,但s1也变了,证明s1的p和s2的p指向的是同一个对象。这在我们有的实际需求中,却不是这样,因而我们需要深拷贝:

     1 class Professor implements Cloneable {
     2     String name;
     3     int age;
     4  
     5     Professor(String name, int age) {
     6         this.name = name;
     7         this.age = age;
     8     }
     9  
    10     public Object clone() {
    11         Object o = null;
    12         try {
    13             o = super.clone();
    14         } catch (CloneNotSupportedException e) {
    15             System.out.println(e.toString());
    16         }
    17         return o;
    18     }
    19 }
    20  
    21 class Student implements Cloneable {
    22     String name;
    23     int age;
    24     Professor p;
    25  
    26     Student(String name, int age, Professor p) {
    27         this.name = name;
    28         this.age = age;
    29         this.p = p;
    30     }
    31  
    32     public Object clone() {
    33         Student o = null;
    34         try {
    35             o = (Student) super.clone();
    36         } catch (CloneNotSupportedException e) {
    37             System.out.println(e.toString());
    38         }
    39         o.p = (Professor) p.clone();
    40         return o;
    41     }
    42 }
    43  
    44 public class DeepCopy {
    45     public static void main(String args[]) {
    46         long t1 = System.currentTimeMillis();
    47         Professor p = new Professor("wangwu", 50);
    48         Student s1 = new Student("zhangsan", 18, p);
    49         Student s2 = (Student) s1.clone();
    50         s2.p.name = "lisi";
    51         s2.p.age = 30;
    52         System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age);// 学生1的教授不改变。
    53         long t2 = System.currentTimeMillis();
    54         System.out.println(t2-t1);
    55     }
    56 }

    当然我们还有一种深拷贝方法,就是将对象串行化:

     1 import java.io.*;
     2 //Serialization is time-consuming
     3 class Professor2 implements Serializable {
     4     /**
     5      * 
     6      */
     7     private static final long serialVersionUID = 1L;
     8     String name;
     9     int age;
    10  
    11     Professor2(String name, int age) {
    12         this.name = name;
    13         this.age = age;
    14     }
    15 }
    16  
    17 class Student2 implements Serializable {
    18     /**
    19      * 
    20      */
    21     private static final long serialVersionUID = 1L;
    22     String name;// 常量对象。
    23     int age;
    24     Professor2 p;// 学生1和学生2的引用值都是一样的。
    25  
    26     Student2(String name, int age, Professor2 p) {
    27         this.name = name;
    28         this.age = age;
    29         this.p = p;
    30     }
    31  
    32     public Object deepClone() throws IOException, OptionalDataException,
    33             ClassNotFoundException {
    34         // 将对象写到流里
    35         ByteArrayOutputStream bo = new ByteArrayOutputStream();
    36         ObjectOutputStream oo = new ObjectOutputStream(bo);
    37         oo.writeObject(this);
    38         // 从流里读出来
    39         ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
    40         ObjectInputStream oi = new ObjectInputStream(bi);
    41         return (oi.readObject());
    42     }
    43  
    44 }
    45  
    46 public class DeepCopy2 {
    47  
    48     /**
    49      * @param args
    50      */
    51     public static void main(String[] args) throws OptionalDataException,
    52             IOException, ClassNotFoundException {
    53         long t1 = System.currentTimeMillis();
    54         Professor2 p = new Professor2("wangwu", 50);
    55         Student2 s1 = new Student2("zhangsan", 18, p);
    56         Student2 s2 = (Student2) s1.deepClone();
    57         s2.p.name = "lisi";
    58         s2.p.age = 30;
    59         System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); // 学生1的教授不改变。
    60         long t2 = System.currentTimeMillis();
    61         System.out.println(t2-t1);
    62     }
    63  
    64 }

    但是串行化却很耗时,在一些框架中,我们便可以感受到,它们往往将对象进行串行化后进行传递,耗时较多。

    ---------------------------------------------------------------------------------------------------------------

    注:本文转载于:http://www.cnblogs.com/shuaiwhu/archive/2010/12/14/2065088.html,感谢原文作者!

  • 相关阅读:
    Zookeeper数据类型
    Zookeeper基本命令
    Redis集群
    Mysql 模拟自增主键
    git回滚版本操作
    Redis缓存穿透和雪崩
    日期格式jackson格式化
    Zookeeper安装
    redis主从复制
    Redis哨兵模式
  • 原文地址:https://www.cnblogs.com/GISQZC/p/5643793.html
Copyright © 2020-2023  润新知