【java开发系列】—— 深克隆和浅克隆
Java支持我们对一个对象进行克隆,通常用在装饰模式和原型模式中。那么什么是深克隆,什么是浅克隆呢。
【浅克隆】,通常只是对克隆的实例进行复制,但里面的其他子对象,都是共用的。
【深克隆】,克隆的时候会复制它的子对象的引用,里面所有的变量和子对象都是又额外拷贝了一份。
下面的两个例子可以很好的说明他们的区别:
首先看一下类图
Husband类有一个对wife的引用,当进行浅克隆的时,wife变量都会指向同一个Wife;而进行深克隆时,会指向不同的Wife。下面进行一下验证:
【浅克隆】
1 public Object clone() { 2 Husband husband = null; 3 try{ 4 husband = (Husband)super.clone(); 5 }catch(CloneNotSupportedException e){ 6 e.printStackTrace(); 7 }finally{ 8 return husband; 9 } 10 }
【深克隆】
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 }
【全部代码】
1 package com.xingoo.clone; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.ByteArrayOutputStream; 5 import java.io.IOException; 6 import java.io.ObjectInputStream; 7 import java.io.ObjectOutputStream; 8 import java.io.Serializable; 9 import java.util.Date; 10 11 class Wife implements Serializable{ 12 private String name; 13 private Date birthday; 14 15 public Wife(){ 16 name = "芙蓉姐姐"; 17 birthday = new Date(); 18 } 19 public Date getBirthday(){ 20 return birthday; 21 } 22 23 public String getName() { 24 return name; 25 } 26 public void setName(String name) { 27 this.name = name; 28 } 29 } 30 class Husband implements Cloneable,Serializable{ 31 private Wife wife; 32 private Date birthday; 33 34 public Husband(){ 35 wife = new Wife(); 36 birthday = new Date(); 37 } 38 39 public Wife getWife(){ 40 return wife; 41 } 42 43 public Date getBirthday(){ 44 return birthday; 45 } 46 /** 47 * 浅克隆一个对象 48 */ 49 public Object clone() { 50 Husband husband = null; 51 try{ 52 husband = (Husband)super.clone(); 53 }catch(CloneNotSupportedException e){ 54 e.printStackTrace(); 55 }finally{ 56 return husband; 57 } 58 } 59 /** 60 * 利用串行化深克隆一个对象,把对象以及它的引用读到流里,在写入其他的对象 61 * @return 62 * @throws IOException 63 * @throws ClassNotFoundException 64 */ 65 public Object deepClone() throws IOException,ClassNotFoundException { 66 //将对象写到流里 67 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 68 ObjectOutputStream oos = new ObjectOutputStream(bos); 69 oos.writeObject(this); 70 //从流里读回来 71 ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); 72 ObjectInputStream ois = new ObjectInputStream(bis); 73 return ois.readObject(); 74 } 75 } 76 public class Test { 77 public static void main(String[] args){ 78 try{ 79 Husband husband = new Husband(); 80 System.out.println("husband birthday "+husband.getBirthday().getTime()); 81 System.out.println("wife birthday "+husband.getWife().getBirthday().getTime()); 82 System.out.println(); 83 Husband husband1 = (Husband)husband.clone(); 84 System.out.println("husband1 birthday "+husband1.getBirthday().getTime()); 85 System.out.println("wife birthday "+husband1.getWife().getBirthday().getTime()); 86 System.out.println(); 87 System.out.println("是否是同一个husband "+(husband == husband1)); 88 System.out.println("是否是同一个wife "+ (husband.getWife() == husband1.getWife())); 89 System.out.println(); 90 Husband husband2 = (Husband)husband.deepClone(); 91 System.out.println("husband2 birthday "+husband2.getBirthday().getTime()); 92 System.out.println("wife birthday "+husband2.getWife().getBirthday().getTime()); 93 System.out.println(); 94 System.out.println("是否是同一个husband "+(husband == husband2)); 95 System.out.println("是否是同一个wife "+ (husband.getWife() == husband2.getWife())); 96 }catch(Exception e){ 97 e.printStackTrace(); 98 } 99 } 100 }
【运行结果】
husband birthday 1414247244668 wife birthday 1414247244668 husband1 birthday 1414247244668 wife birthday 1414247244668 是否是同一个husband false 是否是同一个wife true husband2 birthday 1414247244668 wife birthday 1414247244668 是否是同一个husband false 是否是同一个wife false