提出问题
- 现有一个问题,学校要给学生发放十个三好学生的奖状.
- 解决方案
public class Awards {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
Awards awards = new Awards();
awards.setName("张三"+i+1);
}
}
- 执行 main 方法可以得到结果,但是这样也太麻烦了,需要重复的创建十次对象,对于性能该是有一些影响的.
解决问题
- 对于上面的问题,现在有一个解决的方法,那就是使用
原型模式来解决.
原型模式的概念
- 使用原型实例创建对象,通过克隆原型创建新的对象.
public class Awards implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Awards awards = new Awards();
for (int i = 0; i < 10; i++) {
Awards clone = (Awards) awards.clone();
clone.setName("张三"+i +1);
}
}
使用了原型模式必须要让原型对象实现 cloneable 接口,并且重写他的 clone 方法来实现克隆.
原型模式实现的原理
原型模式的克隆实现就是依赖了java 的浅克隆
优点
- 性能比直接new实现对象要好,适用于对性能和安全要求高的场景
- 逃避构造函数的约束,优缺点共存的这特点,因为是直接在内存中克隆的,构造函数不会执行
浅克隆
- 数据类型是基本数据类型的成员变量,浅克隆直接进行值传递,将该属性值直接复制一份给新对象
- 对于数据类型是引用数据类型的成员变量,如对象,数组...,浅克隆会进行引用传递,会该成员变量的内存地址值复制给新对象,因为两个对象都指向了同一块内存地址,所以无论那个对象的成员变量修改都会影响到其他的对象
- 注意: 浅克隆中 String 类型同基本数据类型一样
深克隆
- 会复制对象的所有基本数据类型的成员变量值
- 会为引用数据类型的成员变量申请新的内存地址,并复制每个引用数据类型变量所引用的对象
对象的深克隆会对整个对象进行克隆
深克隆的实现方式
- 重写
clone方法,手动的将引用数据类型克隆一份 - 使用对象序列化的方式,
但是原型对象以及引用数据类型的对象都需要实现 Serializable 接口