原型模式
- 原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
- 原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节
- 工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它
们自己来实施创建,即对象.clone()- 形象的理解:孙大圣拔出猴毛,变出其它孙大圣
浅拷贝:
Person类package copy;
public class Person implements Cloneable{
private int id;
private String name;
private Adddress address;
public Person(int id, String name, Address address) {
super();
this.id = id;
this.name = name;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Adddress address) {
this.address = address;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", address=" + address + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = null;
person = (Person)super.clone();
return person;
}
}
Address 地址类
package copy;
/**
* @author 韩俊涛
*
*/
public class Address {
private int id;
private String address;
public Address(int id, String address) {
super();
this.id = id;
this.address = address;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Adddress [id=" + id + ", address=" + address + "]";
}
}
测试类
package copy;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Person p = new Person(1, "小明",new Adddress(1, "北京"));
Person p1 = (Person)p.clone();
System.out.println(p);
System.out.println(p1);
System.out.println(p.getAddress().hashCode());
System.out.println(p1.getAddress().hashCode());
}
}
测试结果
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Person [id=1, name=小明, address=Address [id=1, address=北京]]
Person [id=1, name=小明, address=Address [id=1, address=北京]]
getAddress.hashCode:366712642
getAddress.hashCode:366712642
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
通过重写clone()方法,并实现cloneable标识接口可实现浅拷贝,但从测试结果来看,浅拷贝拷贝的类的引用类型Address的数据的hashCode值相同,所以浅拷贝只能用于基本数据类型(String)
深拷贝
- 复制对象的所有基本数据类型的成员变量值
- 为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对>象可达的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝
- 深拷贝实现方式1:重写clone方法来实现深拷贝
- 深拷贝实现方式2:通过对象序列化实现深拷贝(推荐)
重写clone方法来实现深拷贝
- 对要拷贝的类实现Cloneable标识接口,重写clone方法
- 对该类的所有引用数据类型数据(除了String)实现Cloneable标识接口,重写clone方法
- 在该类的clone方法中单独处理引用数据类型的数据
public class Person implements Cloneable{
private int id;
private String name;
private Address address;
//此处省略get,set
@Override
protected Object clone() throws CloneNotSupportedException {
Person person = null;
person = (Person)super.clone();
//对引用数据类型单独处理
person.address = (Address)address.clone();
return person;
}
}
public final class Address implements Cloneable{
private int id;
private String address;
//此处省略get,set
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
测试结果
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Person [id=1, name=小明, address=Address [id=1, address=北京]]
Person [id=1, name=小明, address=Address [id=1, address=北京]]
getAddress.hashCode:366712642
getAddress.hashCode:1829164700
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
通过对象序列化实现深拷贝(推荐)
注意,引用数据类型的类也要实现Serializable接口
public Object deepClone(){
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
Person person = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
person = (Person)ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return person;
}
测试结果
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Person [id=1, name=小明, address=Address [id=1, address=北京]]
Person [id=1, name=小明, address=Address [id=1, address=北京]]
getAddress.hashCode:1028566121
getAddress.hashCode:990368553
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++