前言
Prototype原型模式
是一种创建型设计模式,它允许一个对象再创建另外一个可定制的对象。
Java Object中已经提供了一个Clone( )方法,但是要实现原型模式,必须实现Cloneable接口,使用Cloneable接口都不用导入包。
克隆一个对象有两种方式:
浅克隆:copy该对象,然后保留该对象原有的引用。也就是说不克隆该对象的属性。
深克隆:copy该对象,并且把该对象的所有属性也克隆出一份新的。
浅克隆
我们先看一下如下代码的运行结果:
public class School {
private String name;
private String type;
public School(String name, String type){
this.name = name;
this.type = type;
}
/*构造方法、get方法、set方法省略*/
}
public class Student implements Cloneable {
private String name;
private int age;
private School school;
/*构造方法、get方法、set方法省略*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Prototype {
public static void main(String[] args){
School school = new School("AAA","Junior High");
Student studentA = new Student("alex", 0, school);
System.out.println(studentA.toString());
try {
Student studentB = (Student) studentA.clone();
System.out.println(studentB.toString());
System.out.println("======================");
school.setName("BBB");
school.setType("Senior High");
studentA.setName("Jack");
studentA.setAge(10);
System.out.println(studentA.toString());
System.out.println(studentB.toString());
}catch (CloneNotSupportedException e){
e.printStackTrace();
}
}
}
运行结果:
上图的运行结果中,感觉部分属性复制成功(红色字段),部分属性没有复制成功(绿色字段),这是什么原因呢?
我们需要来了解clone()主要做了些什么,创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。
也就是说Student的内部属性中包含有两个引用类型,因此即便使用clone方法,原始对象及其副本引用同一个对象。
那这么实现完全的复制呢,也就是深克隆呢?
深克隆
一个简单直接的想法就是在克隆对象的同时,把该对象的属性也连带着克隆出新的。 这就要求这个被引用的对象必须也要实现Cloneable接口并且实现clone方法。其实此法也是换汤不换药,那有没有更好一点的方法呢?有的,这就是序列化与反序列化
。
public class School implements Serializable{
private String name;
private String type;
public School(String name, String type){
this.name = name;
this.type = type;
}
}
public class Student implements Serializable {
private String name;
private int age;
private School school;
public Student(String name, int age, School school){
this.name = name;
this.age = age;
this.school = school;
/*构造方法、get方法、set方法省略*/
protected Object deepClone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
}
可以看到,对象被完全复制了。
总结
本文介绍了原型模式,并以此引出了浅拷贝和深拷贝两种对象复制方式,希望能对读者有所帮助。