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 + "\n学生s1教授的姓名:" + s1.p.name + "," + "\n学生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,感谢原文作者!

posted @ 2016-07-05 15:25  GISQZC  阅读(323)  评论(0编辑  收藏  举报