原型模式(prototype)
原型模式就是根据模板类复制对象,一般用于创建复杂的或者耗时的实例,因为这种情况下,复制一个已经存在的实例使程序运行更高效;或者创建值相等,只是命名不一样的同类数据,比如在循环中创建对象
区别于用new来创建对象,new创建对象使用的是类的构造方法,new创建出来的对象属性采用的默认值
而通过原型模式创建对象是直接从堆的二进制流中复制,不需要执行类的构造函数,而且创造出来的类属性与原型对象的属性一样,然后也可以修改复制出来的对象的属性值
原型模式一般跟工厂模式一起使用
调用工厂类创建对象时,内部使用原型模式创建对象,而不通过new
实现方式
浅复制
(1)要克隆的类实现cloneable接口,这是一个空接口叫做标记接口,类似Serializable接口,可以序列化的标志,只是告诉虚拟机,这个类的对象可以被复制。
(2)重写clone方法(该方法不属于cloneable接口,属于Object类)
Object 类提供的方法 clone 只是拷贝本对象的基本类型的属性(String类型的数据也会拷贝),而对象内部的数组、引用对象等都不拷贝,也就是复制出来的对象拥有的引用属性都指向原型对象引用属性的地址,这种拷贝就叫做浅拷贝。
创建原型类:
package xidain.lili.prototype;
import java.util.Date;
//原型类
public class Sheep implements Cloneable{
int age;
String name;
Date birthday;
public Sheep() {}
public Sheep(int age, String name, Date birthday) {
super();
this.age = age;
this.name = name;
this.birthday = birthday;
}
//重写克隆方法,权限修饰符修改为public,返回原型类对象
@Override
public Sheep clone() throws CloneNotSupportedException {
return (Sheep) super.clone();//直接调用父类Object的clone方法
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
进行克隆,调用clone会抛出CloneNotSupportedException异常,没有实现Cloneable接口的时候
package xidain.lili.prototype;
import java.util.Date;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
//创建原型对象
Sheep sheep=new Sheep(8,"多利",new Date(123142356476L));
System.out.println(sheep);
System.out.println(sheep.getAge());
System.out.println(sheep.getName());
System.out.println(sheep.getBirthday());
Sheep clonesheep=sheep.clone();
System.out.println(clonesheep);
System.out.println(clonesheep.getAge());
System.out.println(clonesheep.getName());
System.out.println(clonesheep.getBirthday());
}
}
结果
测试浅复制,修改原型对象引用类型的属性,发现克隆对象的引用类型属性值也变化,但是字符串类型的不变:
深复制
那对应于浅复制,深复制就是把原型对象的所有属性都复制,有两种实现方式
①克隆所有引用属性
package xidain.lili.prototype;
import java.util.Date;
//原型类
public class Sheep2 implements Cloneable{
int age;
String name;
Date birthday;
public Sheep2() {}
public Sheep2(int age, String name, Date birthday) {
super();
this.age = age;
this.name = name;
this.birthday = birthday;
}
//重写克隆方法,权限修饰符修改为public,返回原型类对象
@Override
public Sheep2 clone() throws CloneNotSupportedException {
Sheep2 sheep=(Sheep2) super.clone();
sheep.birthday=(Date) this.getBirthday().clone();//clone属性
return sheep;//
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
②序列化实现深复制
需要原型类实现Serializable接口
package xidain.lili.prototype;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
public class Client2 {
public static void main(String[] args) throws CloneNotSupportedException, Exception {
//创建原型对象
Date d=new Date(3473842384l);
Sheep sheep=new Sheep(8,"多利",d);
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
oos.writeObject(sheep);
byte[] sheepbyte=bos.toByteArray();
ByteArrayInputStream bas=new ByteArrayInputStream(sheepbyte);
ObjectInputStream ois=new ObjectInputStream(bas);
Sheep clonesheep=(Sheep) ois.readObject();
d.setTime(99999999999L);
clonesheep.setAge(9);
sheep.setName("少利");
System.out.println(sheep);
System.out.println(sheep.getAge());
System.out.println(sheep.getName());
System.out.println(sheep.getBirthday());
System.out.println(clonesheep);
System.out.println(clonesheep.getAge());
System.out.println(clonesheep.getName());
System.out.println(clonesheep.getBirthday());
}
}