原型模式
原型模式是指用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。适合原型模式的情景如下:程序需要从一个对象出发,得到若干个和其状态相同,并可独立变化其状态的对象时;对象创建需要独立于它的构造方法和表示时;以原型为基础,克隆新的对象,并完善对象实例变量时。
潜复制
如果原型对象的成员变量是值类型,则将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说,原型对象和克隆对象的成员变量指向相同的内存地址。简单来说潜克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量没有复制。
public class Address{
String pro;
String city;
String zip;
public Address(String p, String c, String z){
pro = p;city=c;zip =z;
}
public String getPro() {
return pro;
}
public void setPro(String pro) {
this.pro = pro;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getZip() {
return zip;
}
public void setZip(String zip) {
this.zip = zip;
}
}
public class Student {
String name;
int age;
Address add;
public Student(String name, int age, Address add) {
this.name = name;
this.age = age;
this.add = add;
}
// 利用构造潜复制
public Student(Student s){
this.name = s.getName();
this.age = s.getAge();
this.add = s.getAdd();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAdd() {
return add;
}
public void setAdd(Address add) {
this.add = add;
}
}
测试方法: 发现student 是两个地址,而add地址值并未改变。
@Test
public void testbasClone(){
Address adr = new Address("tianjin","tj","hedong");
Student st1 = new Student("zhang",20,adr);
Student st2 = new Student(st1);
System.out.println(st1);
System.out.println(st2);
System.out.println(st1.getAdd());
System.out.println(st2.getAdd());
}
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Student@157ec23b
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Student@44d64d4e
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Address@1dd74143
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Address@1dd74143
深复制
在深复制中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象。深克隆将原型对象的所有对象引用对象也复制一份给克隆对象。简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也复制。
address中增加构造方法:
public Address(Address address){
this.pro = address.getPro();
this.city = address.getCity();
this.zip = address.getZip();
}
student中修改构造方法:
public Student(Student s){
this.name = s.getName();
this.age = s.getAge();
this.add = new Address(s.getAdd());
}
此时运行测试方法结果如下:(地址全部改变)
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Student@157ec23b
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Student@44d64d4e
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Address@1dd74143
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Address@526a9908
Cloneable 接口实现深浅复制
潜复制
实现cloneable
public class Student implements Cloneable{
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Student@633fd91
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Student@355c94be
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Address@97a145b
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Address@97a145b
深复制
如果用clone深复制需要引用类型也继承cloneable接口:
public class Address implements Cloneable{
@Override
public Object clone() throws CloneNotSupportedException {
Address s = (Address) super.clone();
return s;
}
}
student中需要修改clone
@Override
public Object clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
student.setAdd((Address) add.clone());
return student;
}
测试结果
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Student@60d6fdd4
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Student@66f28a1f
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Address@60a19573
com.example.bootapitest.bookschema.fiveprototype.bacecopy.Address@44a085e5
利用Serializable序列化接口方法
学生类实现两个接口:
public class Student implements Cloneable,Serializable
地址类实现:public class Address implements Serializable
@Override
public Object clone() throws CloneNotSupportedException {
Object object = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
// 从流中读取
ByteArrayInputStream ios = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
object = ois.readObject();
}catch (Exception e){e.printStackTrace();}
return object;
}
运行结果:
com.example.bootapitest.bookschema.fiveprototype.testSerializable.Student@df921b1
com.example.bootapitest.bookschema.fiveprototype.testSerializable.Student@1db7157f
com.example.bootapitest.bookschema.fiveprototype.testSerializable.Address@4db60246
com.example.bootapitest.bookschema.fiveprototype.testSerializable.Address@75e27856