场景案例
原型(Prototype)模式的定义如下:
用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。
深拷贝案例:
public class AppTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student();
student1.setAddress("山东");
student1.setAge(18);
student1.setBirth(new Date(0));
student1.setName("张三");
Student student2 = (Student) student1.clone();
System.out.println(student1 == student2);
System.out.println(student1);
System.out.println(student2);
System.out.println("------------------");
student2.setBirth(new Date());
System.out.println(student1);
System.out.println(student2);
}
}
class Student implements Cloneable{
private String name;
private String address;
private Integer age;
private Date Birth;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirth() {
return Birth;
}
public void setBirth(Date birth) {
Birth = birth;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", age=" + age +
", Birth=" + Birth +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
student.setBirth((Date) student.getBirth().clone());
return student;
}
}
问题:
clone方法, 会不会引起构造器的调用?不会!那么这个clone方法是如何实现克隆 对象的效果呢?
clone方法是直接赋值内存中的2进制。效率更高!
既然clone方法没有引起构造器的调用,那么克隆出的对象,和原先的对象,地址是否一致?? ?不一致!
最终是两个不同空间中的对象。
原型拷贝模式的优点:
- Java自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
- 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。
原型拷贝模式的缺点:
- 需要为每一个类都配置一个 clone 方法
- clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
- 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。
序列化拷贝
public class AppTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student();
student1.setAddress("山东");
student1.setAge(18);
student1.setBirth(new Date(0));
student1.setName("张三");
Student student2 = (Student) student1.clone();
System.out.println(student1 == student2);
System.out.println(student1);
System.out.println(student2);
System.out.println("------------------");
student2.setBirth(new Date());
System.out.println(student1);
System.out.println(student2);
}
}
class Student implements Serializable{
private String name;
private String address;
private Integer age;
private Date Birth;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBirth() {
return Birth;
}
public void setBirth(Date birth) {
Birth = birth;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", age=" + age +
", Birth=" + Birth +
'}';
}
@Override
public Object clone() throws CloneNotSupportedException {
Student student = null;
try {
//写入内存
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(this);
oos.close();
byte[] bytes = out.toByteArray();
ByteArrayInputStream input = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(input);
student = (Student) ois.readObject();
ois.close();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return student;
}
}
序列化拷贝通过把对象拷贝入内存里,然后在读取出来。对于对象嵌套较多的时候,逻辑处理没有那么复杂。
问题:
序列化拷贝会破坏单例模式嘛?应该怎么解决?
会破坏单例模式。重写 readResolve()方法,返回值为单例对象。
public class SerSingletonTest { public static void main(String[] args) throws CloneNotSupportedException { Singleton instance1 = Singleton.getInstance(); Object clone2 = instance1.clone(); System.out.println(clone2 == instance1); } } class Singleton implements Serializable,Cloneable{ /** * 构造方法,外部能new*/ public Singleton() { } /** * * 创建对象实例*/ private volatile static Singleton SINGLETON; /** * 提供一个静态的公有方法,加入双重检查代码,解决线程安全问题,同时解决懒加载问题 * 同时保证了效率,推荐使用*/ public static Singleton getInstance(){ if (SINGLETON == null){ synchronized (Singleton.class){ if (SINGLETON == null){ SINGLETON = new Singleton(); } } } return SINGLETON; } @Override protected Object clone() throws CloneNotSupportedException { Object o = null; try { //写入内存 ByteArrayOutputStream out = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(out); oos.writeObject(this); oos.close(); byte[] bytes = out.toByteArray(); ByteArrayInputStream input = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(input); o = ois.readObject(); ois.close(); } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } return o; } //加入此方法,就会自动调用这个 readResolve方法来返回我们指定好的对象了。 /*public Object readResolve(){ return SINGLETON; }*/ }
这样当JVM从内存中反序列化地"组装"一个新对象时,就会自动调用这个 readResolve方法来返回我们指定好的对象了, 单例规则也就得到了保证.