Cloneable 和clone的区别和联系

设计模式----原型模式时候,涉及到的复制克隆,

    Cloneable 接口,内部是没有任何方法的,

这个接口其实是一个标记性的接口,和Serializable是一样的,都是标记使用,

 

 在类实现了这个Cloneable 接口后调用Object中得clone方法,才可以正常的使用,如果没有implements Cloneable的类调用Object.clone()方法就会抛出CloneNotSupportedException。 

在复制中,分为浅复制和深复制;

先说浅复制:

其实这样的复制是一种很危险的复制,有时候预期效果并不是你想要的!

 1 package Method.clone;
 2 
 3 public class Student implements Cloneable 
 4 {
 5     private int id;
 6     private String name;
 7     public StringBuffer sb = new StringBuffer("");
 8 
 9     public Student() {
10         this.id = 744;
11         this.name = "FL";
12     }
13 
14     public Student(int id, String name) {
15         this.id = id;
16         this.name = name;
17     }
18 
19     public boolean equals(Object obj) {
20         return this.id == ((Student) obj).id;
21     }
22 
23     public String toString() {
24         return "Student id : " + id + " Name " + name;
25     }    
26 
27     public static void main(String[] args) throws CloneNotSupportedException // 这里为什么一定得写
28     {
29         Student s1 = new Student(101, "WangQiang");
30         Student s2 = (Student) s1.clone();
31         System.out.println(s1 == s2);
32         System.out.println(s1);
33         System.out.println(s2);
34 
35         s1.sb.append("s1's string");
36         System.out.println("s2.sb's value = " + s2.sb.toString());
37         System.out.println(s1.sb==s2.sb);
38         
39     }
40 }

 

浅层拷贝导致s1和s2共享同一个StringBuffer对象,s2还是可以调用s1中得StringBuffer。这样的复制还是很危险!

Object中提供的clone方法是一种浅复制,对于基本类型的字段,可以说它成功克隆了。但对于对象型字段,它并没有实现克隆的功能,仅仅做了一个赋值。(拷贝基本成员属性,对于引用类型仅返回指向改地址的引用)

 

 深复制: 

       首先这个对象必须实现了Serializable 接口,可以被序列化,和反序列化:深复制时候采用的是流进行读写的,原对象还是存在JVM中

序列化前和序列化后的对象的关系


反序列化还原后的对象地址与原来的的地址不同,序列化前后对象的地址不同了,但是内容是一样的,而且对象中包含的引用也相同。换句话说,通过序列化操作,我们可以实现对任何可Serializable对象的”深度复制(deep copy)"——这意味着我们复制的是整个对象网,而不仅仅是基本对象及其引用。对于同一流的对象,他们的地址是相同,说明他们是同一个对象,但是与其他流的对象地址却不相同。也就说,只要将对象序列化到单一流中,就可以恢复出与我们写出时一样的对象网,而且只要在同一流中,对象都是同一个。

 

 

 1 public  Object deepClone() throws IOException, ClassNotFoundException{
 2         //将对象写到流里
 3         ByteArrayOutputStream bos = new ByteArrayOutputStream();
 4         ObjectOutputStream oos = new ObjectOutputStream(bos);
 5         oos.writeObject(this);
 6         //从流里读回来
 7         ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
 8         ObjectInputStream ois = new ObjectInputStream(bis);
 9         return ois.readObject();
10     }

对具体分析:参考博客 

 http://www.cnblogs.com/tonyluis/p/5779187.html

 

posted @ 2017-04-09 13:38  指针怒草内存栈  阅读(342)  评论(0编辑  收藏  举报