用于通过拷贝创建重复的对象,同时又能保证性能
**主要解决:**在运行期建立和删除原型。
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、配备克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。
Cloneable接口是一个空接口,使用Cloneable接口都不用导入包。而clone方法是属于Object对象的。如果要克隆某个对象的话必须实现Cloneable接口
浅拷贝和深拷贝
浅拷贝:Object类的clone方法指对拷贝对象的基本类型,对数组,容器对象,引用对象等不会拷贝;
深拷贝:如果实现深拷贝,必须将原型模式中的数组,容器对象,引用对象等另行拷贝;
注意:浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
/**
* @description: 原型模式-浅拷贝
* @author: husy
* @date 2020/3/2
*/
public class Product implements Cloneable {
private String name;
private int[] array;
public Product(String name, int[] array) {
this.name = name;
this.array = array;
}
public void setName(String name) {
this.name = name;
}
public void setArray(int[] array) {
this.array = array;
}
@Override
public String toString() {
return this.name+"--"+ Arrays.toString(this.array);
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Main.java
public static void main(String[] args) throws CloneNotSupportedException {
String name = "喜洋洋";
int array[] = {1,2};
Product product1 = new Product(name,array);
Product product2 =(Product) product1.clone();
System.out.println(product1.toString());
System.out.println(product2.toString());
System.out.println("-------修改字符串和数组的值,测试拷贝情况-------");
product1.setName( "灰太狼");
array[1]=4;
product1.setArray(array);
System.out.println(product1.toString());
System.out.println(product2.toString());
}
输出:
喜洋洋--[1, 2]
喜洋洋--[1, 2]
-------修改字符串和数组的值,测试拷贝情况-------
灰太狼--[1, 4]
喜洋洋--[1, 4] //-->> 数组中第二个值被改变了--<<
有上可知,放我们修改最后结果,克隆对象仍保留原有数组对象的引用,值随着改变而改变,
如果要想解决这种问题,以达到深拷贝的目的,可以将数组,容器对象,引用对象都进行一次拷贝,如下可以将Product 类中的 Clone 方法修改一下,将数组也拷贝一次,其他不变
@Override
protected Object clone() throws CloneNotSupportedException {
// return super.clone();
Product product = (Product) super.clone();
product.array=this.array.clone(); // 将数组也拷贝一次
return product;
}
执行,结果如下:
喜洋洋--[1, 2]
喜洋洋--[1, 2]
-------修改字符串和数组的值,测试拷贝情况-------
灰太狼--[1, 4]
喜洋洋--[1, 2]
最结果看出,对象所有属性都进行可控了,修改product1的属性,不会改变product2的属性
创建序列化拷贝对象SerializedClone
public class SerializedClone {
public static <T extends Serializable> T clone(T obj) {
T cloneObj = null;
try {
//写入字节流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close();
//分配内存,写入原始对象,生成新对象
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
//返回生成的新对象
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
}
测试:
String name1 = "喜洋洋";
int[] array1 = {10,12};
Product product3 = new Product(name1,array1);
Product product4 = SerializedClone.clone(product3);
System.out.println(product3.toString());
System.out.println(product4.toString());
System.out.println("-------修改属性");
array[1]=3;
product1.setArray(array);
System.out.println(product3.toString());
System.out.println(product4.toString());
输出如下:
喜洋洋--[10, 12]
喜洋洋--[10, 12]
-------修改属性
喜洋洋--[10, 12]
喜洋洋--[10, 12]
序列化拷贝并不会因原型对象的属性值改变而发生变化