浅克隆与深克隆
1、浅克隆
1.1、什么是浅克隆?
被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然
指向原来的对象(克隆对象与原型对象共享引用数据类型变量)。
如下图所示:
1.2、浅克隆代码实现
类实现接口 Cloneable,表示该类的对象是可以克隆的
示例代码1:
public class ConcretePrototype implements Cloneable {public ConcretePrototype() {System.out.println("具体的对象创建完成!");}@Overrideprotected ConcretePrototype clone() throws CloneNotSupportedException {System.out.println("具体的对象复制成功!");return (ConcretePrototype)super.clone();}
}
测试
@Testpublic void test01() throws CloneNotSupportedException {ConcretePrototype c1 = new ConcretePrototype();ConcretePrototype c2 = c1.clone();System.out.println("对象c1和c2是同一个对象?" + (c1 == c2));}
打印结果:
对象c1和c2是同一个对象?true
示例代码2:
在 类 ConcretePrototype 中添加一个引用类型的属性Person,如下所示:
public class ConcretePrototype implements Cloneable {private Person person;public Person getPerson() {return person;}public void setPerson(Person person) {this.person = person;}void show(){System.out.println("嫌疑人姓名: " +person.getName());}public ConcretePrototype() {System.out.println("具体的对象创建完成!");}@Overrideprotected ConcretePrototype clone() throws CloneNotSupportedException {System.out.println("具体的对象复制成功!");return (ConcretePrototype)super.clone();}}public class Person {private String name;public Person() {}public Person(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
测试:
@Testpublic void test02() throws CloneNotSupportedException {ConcretePrototype c1 = new ConcretePrototype();Person p1 = new Person();c1.setPerson(p1);//复制c1ConcretePrototype c2 = c1.clone();//获取复制对象c2中的Person对象Person p2 = c2.getPerson();p2.setName("慕容复");//判断p1与p2是否是同一对象System.out.println("p1和p2是同一个对象?" + (p1 == p2));c1.show();c2.show();}
打印结果:
p1和p2是同一个对象?true
嫌疑人姓名:慕容复
嫌疑人姓名:慕容复
p1与p2是同一对象,这是浅克隆的效果,也就是对具体原型类中的引用数据类型的属性进行
引用的复制
2、深克隆
2.1、什么是深克隆
除去那些引用其他对象的变量,被复制对象的所有变量都含有与原来的对象相同的值。那些
引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言
之,深复制把要复制的对象所引用的对象都复制了一遍。如下图所示:
2.2、深克隆代码实现
对于上边浅克隆示例2中的代码,如果有需求场景中不允许共享同一对象,那么就需要使用
“深拷贝”,如果想要进行深拷贝需要使用到对象序列化流 (对象序列化之后,再进行反序列化
获取到的是不同对象)。代码如下
@Testpublic void test03() throws Exception {ConcretePrototype c1 = new ConcretePrototype();Person p1 = new Person("峰哥");c1.setPerson(p1);//创建对象序列化输出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("c.txt"));//将c1对象写到文件中oos.writeObject(c1);oos.close();//创建对象序列化输入流ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c.txt"));//读取对象ConcretePrototype c2 = (ConcretePrototype) ois.readObject();Person p2 = c2.getPerson();p2.setName("凡哥");//判断p1与p2是否是同一个对象System.out.println("p1和p2是同一个对象?" + (p1 == p2));c1.show();c2.show();}
3、总结
1)Java中的Object类中提供了 `clone()` 方法来实现“浅克隆”。需要注意的是要想实现克隆
的Java类必须实现一个标识接口 Cloneable ,来表示这个Java类支持被复制。
2)其实现在不推荐大家用Cloneable接口,实现比较麻烦,现在借助Apache Commons或
者springframework可以直接实现:
(1)浅克隆:BeanUtils.cloneBean(Object obj);
BeanUtils.copyProperties(S,T);
(2)深克隆:SerializationUtils.clone(T object);
BeanUtils是利用反射原理获得所有类可见的属性和方法,然后复制到target类。
SerializationUtils.clone()就是使用我们的前面讲的序列化实现深克隆,当然你要把要克隆
的类实现Serialization接口。