深拷贝和浅拷贝

  • 浅拷贝:只拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象。

或者说,被复制对象的所有变量都含有与原来的对象相同的值,对象的引用对象会在原来的对象和它的副本之间共享。 调用clone()得到的对象。

 

  • 深拷贝:不仅拷贝对象本身,而且拷贝对象包含引用指向的所有对象。    

简而言之,深拷贝把要复制的对象所引用的对象都复制了一遍。即对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容。override clone()得到的对象,

对其内的引用类型的变量,再进行一次 clone()。或者使用序列化。


范例:
    对象A1中包含对B1的引用,B1中包含对C1的引用。
    浅拷贝A1得到A2,A2中依然包含对B1的引用,B1中依然包含对C1的引用。
    深拷贝则是对浅拷贝的递归,深拷贝A1得到A2,A2中包含对B2(B1的copy)的引用,B2中包含对C2(C1的copy)的引用。

范例:浅拷贝
1.实体类 - Professor0

 1 public class Professor0 implements Cloneable {
 2 
 3     public String name;
 4     
 5     public int age;
 6 
 7     public Professor0(String name, int age) {
 8         this.name = name;
 9         this.age = age;
10     }
11     
12     public Object clone() throws CloneNotSupportedException {
13         return super.clone();
14     }
15     
16     
17 
18 }


2.实体类 - Student0

 1 public class Student0 implements Cloneable {
 2 
 3     public String name;
 4     public int age;
 5     public Professor0 p;
 6     public Student0(String name, int age, Professor0 p) {
 7         this.name = name;
 8         this.age = age;
 9         this.p = p;
10     }
11     
12     public Object clone() {
13         Student0 o = null;
14         try {
15             o = (Student0) super.clone();
16         } catch (CloneNotSupportedException e) {
17             System.out.println(e.toString());
18         }
19         return o;
20     }
21     
22     
23     
24     
25 }


3.浅拷贝类 - ShallowCopy

 1 public class ShallowCopy {
 2 
 3     public static void main(String[] args) {
 4         Professor0 p = new Professor0("张三", 50);
 5         Student0 s1 = new Student0("李四", 18, p);
 6         Student0 s2 = (Student0) s1.clone();
 7         s2.p.name = "王五";
 8         s2.p.age = 30;
 9         s2.name = "赵六";
10         s2.age = 45;
11         System.out.println("学生s1的姓名:" + s1.name + "\n学生s1教授的姓名:" + s1.p.name + ",\n学生s1教授的年龄:" + s1.p.age);
12     }
13     
14 }

结果:    学生s1的姓名:李四
        学生s1教授的姓名:王五,
        学生s1教授的年龄:30
        
总结:s2.p变了,s1.p也变了,证明s1的p和s2的p指向的是同一个对象

范例:深拷贝
1.实体类 - Professor

 1 public class Professor implements Cloneable {
 2 
 3     public String name;
 4     
 5     public int age;
 6 
 7     public Professor(String name, int age) {
 8         this.name = name;
 9         this.age = age;
10     }
11     
12     public Object clone(){
13         Object o = null;
14         try {
15             o = super.clone();
16         } catch (CloneNotSupportedException e) {
17             System.out.println(e.toString());
18         }
19         return o;
20     }
21     
22     
23 
24 }


2.实体类 - Student

 1 public class Student implements Cloneable {
 2 
 3     public String name;
 4     public int age;
 5     public Professor p;
 6     public Student(String name, int age, Professor p) {
 7         this.name = name;
 8         this.age = age;
 9         this.p = p;
10     }
11     
12     public Object clone() {
13         Student o = null;
14         try {
15             o = (Student) super.clone();
16         } catch (CloneNotSupportedException e) {
17             System.out.println(e.toString());
18         }
19         o.p = (Professor) p.clone();
20         return o;
21     }
22     
23     
24     
25     
26 }


3.深拷贝类 - DeepCopy

 1 public class DeepCopy {
 2 
 3     public static void main(String[] args) {
 4         
 5         long t1 = System.currentTimeMillis();
 6         Professor p = new Professor("张三", 50);
 7         Student s1 = new Student("李四", 18, p);
 8         Student s2 = (Student) s1.clone();
 9         s2.p.name = "王五";
10         s2.p.age = 30;
11         System.out.println("学生s1的姓名:" + s1.name + "\n学生s1教授的姓名:" + s1.p.name + ",\n学生s1教授的年龄:" + s1.p.age);
12         long t2 = System.currentTimeMillis();
13         System.out.println(t2-t1);
14     }
15     
16 }

结果:    学生s1的姓名:李四
        学生s1教授的姓名:张三,
        学生s1教授的年龄:50
        1

总结:s2.p变了,s1.p没变。证明s1的p和s2的p指向的不是同一个对象

范例:采用序列化实现深拷贝
1.实体类 - Professor2

 1 public class Professor2 implements Serializable {
 2     private static final long serialVersionUID = 1L;
 3 
 4     public String name;
 5     
 6     public int age;
 7 
 8     public Professor2(String name, int age) {
 9         this.name = name;
10         this.age = age;
11     }
12     
13 
14 }


2.实体类 - Student2

 1 public class Student2 implements Serializable {
 2     private static final long serialVersionUID = 1L;
 3     public String name;
 4     public int age;
 5     public Professor2 p;
 6     
 7     public Student2(String name, int age, Professor2 p) {
 8         this.name = name;
 9         this.age = age;
10         this.p = p;
11     }
12     
13     public Object deepClone() throws IOException, ClassNotFoundException {
14 //        将对象写到流里
15         ByteArrayOutputStream bo = new ByteArrayOutputStream();
16         ObjectOutputStream oo = new ObjectOutputStream(bo);
17         oo.writeObject(this);
18 //        从流里读出来
19         ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
20         ObjectInputStream oi = new ObjectInputStream(bi);
21         return oi.readObject();
22         
23     }
24     
25 }


3.深拷贝类 - DeepCopy2

 1 public class DeepCopy2 {
 2 
 3     public static void main(String[] args) throws ClassNotFoundException, IOException {
 4         
 5         long t1 = System.currentTimeMillis();
 6         Professor2 p = new Professor2("张三", 50);
 7         Student2 s1 = new Student2("李四", 18, p);
 8         Student2 s2 = (Student2) s1.deepClone();
 9         s2.p.name = "王五";
10         s2.p.age = 30;
11         System.out.println("学生s1的姓名:" + s1.name + "\n学生s1教授的姓名:" + s1.p.name + ",\n学生s1教授的年龄:" + s1.p.age);
12         long t2 = System.currentTimeMillis();
13         System.out.println(t2-t1);
14     }
15     
16 }

结果:    学生s1的姓名:李四
        学生s1教授的姓名:张三,
        学生s1教授的年龄:50
        85

总结:s2.p变了,s1.p没变。证明s1的p和s2的p指向的不是同一个对象。相比实现Cloneable,实现Serializable更耗时。


posted @ 2016-08-09 11:17  Ivy_Xu  阅读(179)  评论(0编辑  收藏  举报