java浅拷贝和深拷贝

java语言本身具有对对象的复制功能,Java.lang.Object具有受保护的clone()方法, 使用这个方法的前提是要实现Cloneable接口,调用clone()方法返回的克隆对象是一种“浅克隆”,什么意思呢?就是这种克隆“不彻底”,也就是克隆对象和原对象还有千丝万缕的联系,先拿一个例子证明一下:

 1 package clone;
 2 
 3 public class JavaClone {
 4     public static void main(String[] args) {
 5         student stu1=new student("zhangsan");
 6         professor pro1=new professor("professor");
 7         stu1.setProfessor(pro1);
 8         student stu2=(student) stu1.clone();
 9         System.out.println("stu1.getClass()==stu2.getClass() ? "+(stu1.getClass()==stu2.getClass()));
10         System.out.println("stu1==stu2 ? "+(stu1==stu2));
11         //验证原对象和拷贝对象引用的对其他是否一致
12         System.out.println("stu1.getProfessor()==stu2.getProfessor() ? "+(stu1.getProfessor()==stu2.getProfessor()));
13     }
14 }
15 
16 class student implements Cloneable{
17     //定义一个对其他类对象的引用
18     private professor professor;
19     private String name;
20     public student(String name){
21         this.setName(name);
22     }
23     public Object clone(){
24         Object copyObject=null;
25         try {
26             copyObject=super.clone();
27         } catch (CloneNotSupportedException e) {
28             e.printStackTrace();
29         }
30         return copyObject;
31     }
32     public professor getProfessor() {
33         return professor;
34     }
35     public void setProfessor(professor professor) {
36         this.professor = professor;
37     }
38     public String getName() {
39         return name;
40     }
41     public void setName(String name) {
42         this.name = name;
43     }
44 }
45 class professor {
46     private String name;
47     public professor(String name){
48         this.setName(name);
49     }
50     public String getName() {
51         return name;
52     }
53     public void setName(String name) {
54         this.name = name;
55     }
56 }
View Code

运行程序,可得如下结果:

stu1.getClass()==stu2.getClass() ? true
stu1==stu2 ? false
stu1.getProfessor()==stu2.getProfessor() ? true

第一行没得说,原对象和克隆对象的运行时类当然是同一个类了,都是student类,第二行也没得说,原对象和克隆对象不是同一个对象,否则也不叫“克隆”了,而第三行就有些古怪了,原对象对其他对象的引用和克隆对象对其他对象的引用竟然是相同的!而这正是“浅克隆”的特征:原有对象的变量与克隆对象的变量具有相同的值,它们对其他对象的引用都是相同的,也就是克隆对象对其他对象的引用和原对象对其他对象的引用是同一个引用,“浅克隆”并未做到对对象中引用的克隆,所以说,这种克隆不是彻底的。那么,怎样才能做到对对象中的所有内容都克隆一遍呢?这就是深克隆要做的事了, 先看例子:

 1 package clone;
 2 
 3 import java.io.ByteArrayInputStream;
 4 import java.io.ByteArrayOutputStream;
 5 import java.io.ObjectInputStream;
 6 import java.io.ObjectOutputStream;
 7 import java.io.Serializable;
 8 
 9 public class JavaClone {
10     public static void main(String[] args) {
11         student stu1=new student("zhangsan");
12         professor pro1=new professor("professor");
13         stu1.setProfessor(pro1);
14         student stu2=(student) stu1.deepclone();
15         System.out.println("stu1.getClass()==stu2.getClass() ? "+(stu1.getClass()==stu2.getClass()));
16         System.out.println("stu1==stu2 ? "+(stu1==stu2));
17         //验证原对象和拷贝对象引用的对其他是否一致
18         System.out.println("stu1.getProfessor()==stu2.getProfessor() ? "+(stu1.getProfessor()==stu2.getProfessor()));
19     }
20 }
21 
22 class student implements Cloneable,Serializable{
23     /**
24      * 
25      */
26     private static final long serialVersionUID = 827518515795699774L;
27     //定义一个对其他类对象的引用
28     private professor professor;
29     private String name;
30     public student(String name){
31         this.setName(name);
32     }
33     public Object deepclone(){
34         Object copyObject=null;
35         try {
36             ByteArrayOutputStream bo=new ByteArrayOutputStream();
37             ObjectOutputStream oo=new ObjectOutputStream(bo);
38             oo.writeObject(this);
39             ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
40             ObjectInputStream oi=new ObjectInputStream(bi);
41             return oi.readObject();
42         } catch (Exception e) {
43             e.printStackTrace();
44         }
45         return copyObject;
46     }
47     public professor getProfessor() {
48         return professor;
49     }
50     public void setProfessor(professor professor) {
51         this.professor = professor;
52     }
53     public String getName() {
54         return name;
55     }
56     public void setName(String name) {
57         this.name = name;
58     }
59 }
60 class professor implements Cloneable,Serializable{
61     /**
62      * 
63      */
64     private static final long serialVersionUID = 7201762075804205074L;
65     private String name;
66     public professor(String name){
67         this.setName(name);
68     }
69     public String getName() {
70         return name;
71     }
72     public void setName(String name) {
73         this.name = name;
74     }
75 }
View Code

运行结果如下:

stu1.getClass()==stu2.getClass() ? true
stu1==stu2 ? false
stu1.getProfessor()==stu2.getProfessor() ? false

这里用到了串行化技术,所谓“串行化”就是将对象写到流里的过程,把对象从流中读出来的称为“并行化”,这里写到流里面的对象是一个拷贝,源对象仍在JVM中,当我们将流里的这份拷贝又写到JVM中,相当于又创建了一个和原来对象内容一样的对象,但是二者是不同的对象,这样就实现了克隆时将对象中不管是引用还是非引用的变量都进行了一遍复制,这就是“深克隆”。

注意一点,在深克隆时,所有的类均要实现java.io.Serializable接口,因为什么?因为我们需要将对象写到流里并再从流里读出对象。总结到此,晚安,睡个好觉...

原文地址:https://www.cnblogs.com/codeMedita/p/6974287.html