对象的克隆
1、克隆即复制的意思,对象的克隆,意味着生成一个对象,这个对象和某个对象的属性和行为是一致的,但是这个对象和源对象是两个不同的对象。实现对象的克隆,方法是实现Cloneable接口,否则会报异常CloneNotSupportedException
1 public class Demo implements Cloneable{ 2 private int number; 3 private String name; 4 5 public int getNumber() { 6 return number; 7 } 8 public void setNumber(int number) { 9 this.number = number; 10 } 11 public String getName() { 12 return name; 13 } 14 public void setName(String name) { 15 this.name = name; 16 } 17 18 19 public static void main(String[] args) { 20 Demo demo = new Demo(); 21 Demo demo2 = null; 22 try { 23 demo2 = (Demo) demo.clone(); 24 System.out.println(demo==demo2); 25 26 } catch (CloneNotSupportedException e) { 27 e.printStackTrace(); 28 } 29 } 30 }
输出:
false
从结果我们可以知道,两个引用指向的对象是两个不同的Demo对象.
2、浅克隆
浅克隆是指在克隆对象的时候,对于对象中的属性的值进行复制,那么这里引出一个问题,如对象的成员变量不论是基本类型还是引用类型,克隆对象的成员变量的值与源对象一致,这里引出一个问题,当成员变量是引用类型的时候,克隆对象和源对象的引用成员类型变量指向的是同一个对象,那么当这个对象本身的内容发生改动的时候,势必影响到克隆对象和源对象,这样在实际的生产过程可能带来巨大问题。因此对象的克隆只在特定的场景下使用。
浅克隆的例子:
1 public class Demo implements Cloneable{ 2 private int number; 3 private Person person; 4 public int getNumber() { 5 return number; 6 } 7 public void setNumber(int number) { 8 this.number = number; 9 } 10 public Person getPerson() { 11 return person; 12 } 13 public void setPerson(Person person) { 14 this.person = person; 15 } 16 17 public static void main(String[] args) { 18 Demo demo = new Demo(); 19 demo.setNumber(10); 20 Person person = new Person(); 21 person.setName("test"); 22 demo.setPerson(person); 23 Demo demo2 = null; 24 try { 25 demo2 = (Demo) demo.clone(); 26 //很明显,源对象和克隆对象的引用类型变量指向同一个Person对象 27 System.out.println(demo.getPerson()==demo2.getPerson()); 28 System.out.println(demo.getPerson().getName()+":"+demo2.getPerson().getName()); 29 //person对象发生变动 30 person.setName("demo"); 31 System.out.println(demo.getPerson().getName()+":"+demo2.getPerson().getName()); 32 33 } catch (CloneNotSupportedException e) { 34 e.printStackTrace(); 35 } 36 } 37 } 38 39 class Person{ 40 private String name; 41 42 public String getName() { 43 return name; 44 } 45 public void setName(String name) { 46 this.name = name; 47 } 48 }
输出结果:
true test:test demo:demo
3、深克隆
在克隆时引用类型的变量在源对象和克隆对象中指向同一个对象。那么能否做到克隆出来的对象的引用属性指向的对象与源对象是两个不同的对象呢?答案是可以的,这种克隆被称为深克隆。与浅克隆区别在于,复制对象的时候,是否对源对象中的引用变量指向的对象进行拷贝。进行深克隆的常用的手段是通过流和序列化/反序列化来实现。
1 public class Demo implements Serializable{ 2 private int number; 3 private Person person; 4 public int getNumber() { 5 return number; 6 } 7 public void setNumber(int number) { 8 this.number = number; 9 } 10 public Person getPerson() { 11 return person; 12 } 13 public void setPerson(Person person) { 14 this.person = person; 15 } 16 17 public static void main(String[] args){ 18 Demo demo = new Demo(); 19 demo.setNumber(10); 20 Person person = new Person(); 21 person.setName("test"); 22 demo.setPerson(person); 23 Demo demo2 = ObjectUtil.clone(demo); 24 System.out.println(demo.getPerson()==demo2.getPerson()); 25 System.out.println(demo.getPerson().getName()+":"+demo2.getPerson().getName()); 26 //person对象发生变动 27 person.setName("demo"); 28 System.out.println(demo.getPerson().getName()+":"+demo2.getPerson().getName()); 29 } 30 } 31 32 class Person implements Serializable{ 33 private String name; 34 35 public String getName() { 36 return name; 37 } 38 public void setName(String name) { 39 this.name = name; 40 } 41 }
工具类:
1 public class ObjectUtil { 2 @SuppressWarnings("unchecked") 3 public static <T>T clone(T obj){ 4 T clonedObj = null; 5 try { 6 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 7 //将对象写进字节流中 8 ObjectOutputStream oos = new ObjectOutputStream(baos); 9 oos.writeObject(obj); 10 //从字节流中读出对象 11 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); 12 ObjectInputStream ois = new ObjectInputStream(bais); 13 clonedObj = (T)ois.readObject(); 14 }catch (IOException e) { 15 e.printStackTrace(); 16 }catch (ClassNotFoundException e) { 17 e.printStackTrace(); 18 } 19 return clonedObj; 20 } 21 }