一、浅拷贝
1、对于数据类型是基本数据类型的成员变量,浅拷贝会直接直接值传递,也就是将该属性值复制一份给新的对象;
2、对于数据类型是引用数据的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值;
3、前面的克隆羊就是浅拷贝,默认调用 clone() 方法来实现的;
String拷贝的特殊性:
String 类型很特殊,它是不可变类型,即一旦初始化后,就不可以改变。因为他为引用型,而且他指向的值为常量,克隆出来的对象改变他的值,实际上是改变了克隆出来对象String类型成员的指向,不会影响被克隆对象的。
解释:如果原来对象的一个string变量进行初始化的时候,指向的是一个字符串常量,该字符串常量会被放到常量池中,该string类型的引用将会指向该常量。进行克隆后,得到一个新的对象,如果该对象的string变量重新赋值,那么只会有这个string 引用变量指向一个新的内存区域,对原来对象中的string变量不会有影响。
克隆相当于 1 个 String 内存空间有两个引用,当修改其中的一个值的时候,会新分配一块内存用来保存新的值,这个引用指向新的内存空间,原来的 String 因为还存在指向他的引用,所以不会被回收,这样,虽然是复制的引用,但是修改值的对象,并没有改变被复制对象的值。
二、深拷贝
1、复制对象的所有基本数据类型的成员变量值;
2、为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就说,对象进行深拷贝要对整个对象进行拷贝;
3、深拷贝实现方式1:重写 clone 方法来实现深拷贝;
4、深拷贝实现方式2:通过对象序列化实现深拷贝(推荐使用)
三、深拷贝代码实现:
代码实现:
1 public class DeepCloneableTarget implements Serializable, Cloneable {
2
3
4 private static final long serialVersionUID = -8179039019334069484L;
5
6 private String cloneName;
7 private String cloneClass;
8
9 public DeepCloneableTarget(String cloneName, String cloneClass) {
10 this.cloneName = cloneName;
11 this.cloneClass = cloneClass;
12 }
13
14 /**
15 * 因为该类的属性,都是String , 因此我们这里使用默认的clone完成即可
16 * @return
17 * @throws CloneNotSupportedException
18 */
19 @Override
20 protected Object clone() throws CloneNotSupportedException {
21 return super.clone();
22 }
23 }
24
25 -----------------------------------------
26 public class DeepProtoType implements Serializable, Cloneable {
27
28 private static final long serialVersionUID = -948045492482458361L;
29
30 public String name; //String 属性
31 public DeepCloneableTarget deepCloneableTarget; // 引用类型
32
33 public DeepProtoType() {
34 }
35
36 /**
37 * 深克隆,方式1:使用 clone 方法
38 * @return
39 * @throws CloneNotSupportedException
40 */
41 @Override
42 protected Object clone() throws CloneNotSupportedException {
43 Object deep = null;
44 //这里完成对基本数据类型(属性)和String的克隆
45 deep = super.clone();
46 //对引用类型的属性,进行单独处理
47 DeepProtoType deepProtoType = (DeepProtoType)deep;
48
49 deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();
50
51 return deepProtoType;
52 }
53
54 /**
55 * 深拷贝 方式二:通过对象的序列化实现(推荐)
56 * @return
57 */
58 public Object deepClone() {
59 //创建流对象
60 ByteArrayOutputStream bos = null;
61 ObjectOutputStream oos = null;
62 ByteArrayInputStream bis = null;
63 ObjectInputStream ois = null;
64
65 try {
66 //序列化
67 bos = new ByteArrayOutputStream();
68 oos = new ObjectOutputStream(bos);
69 //当前这个对象以对象流的方式输出
70 oos.writeObject(this);
71
72 //反序列化
73 bis = new ByteArrayInputStream(bos.toByteArray());
74 ois = new ObjectInputStream(bis);
75 DeepProtoType copyObj = (DeepProtoType)ois.readObject();
76
77 return copyObj;
78 } catch (Exception e) {
79 e.printStackTrace();
80 return null;
81 } finally {
82 //关闭流
83 try {
84 bos.close();
85 oos.close();
86 bis.close();
87 ois.close();
88 } catch (IOException e2) {
89 System.out.println(e2.getMessage());
90 }
91 }
92 }
93 }
94
95 ---------------Test测试----------------------
96 public class Client {
97
98 public static void main(String[] args) throws Exception {
99 DeepProtoType p = new DeepProtoType();
100 p.name = "宋江";
101 p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛");
102
103 //方式1 完成深拷贝
104
105 DeepProtoType p2 = (DeepProtoType) p.clone();
106
107 System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
108 System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p2.deepCloneableTarget.hashCode());
109
110 //方式2 完成深拷贝
111 DeepProtoType p3 = (DeepProtoType) p.deepClone();
112
113 System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
114 System.out.println("p2.name=" + p.name + "p2.deepCloneableTarget=" + p3.deepCloneableTarget.hashCode());
115
116 }
117 }