原型模式是指用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。适用原型实例的场景如下:程序需要从一个对象出发,得到若干个和其状态相同,并可独立变化其状态的对象时;对象创建需要独立于它的构造方法和表示时;以原型对象为基础,并完善对象实例变量是。
在计算机程序开发过程中,有时需要为一个实例创建多个实例的情况,这些实例内部成员往往完全相同或有细微的差异,而且实例的创建开销比较大或者需要输入较多参数。如果能通过复制一个已创建的对象实例来重复创建多个相同的对象,这就可以大大减少创建对象的开销,这个时候就需要原型模式。
原型模式复制功能分为浅复制和深复制两种情况。
现在考虑对学生对象的复制问题。
Student.java
public class Student {
private String name; //姓名
private int age; //年龄
Address add; //地址
public Student(String name, int age, Address add) {
this.name = name;
this.age = age;
this.add = add;
}
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;
}
}
Address.java
public class Address {
private String pro; //省份
private String city; //城市
private String zip;//邮编
public Address(String pro, String city, String zip) {
this.pro = pro;
this.city = city;
this.zip = zip;
}
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;
}
}
方法一:利用构造函数方法实现对Student类的复制
1.浅复制
Student.java
//其他代码同上
public Student(Student s) {
this.name = s.getName();
this.age = s.getAge();
this.add = s.getAdd();
}
Test.java(测试类)
public static void main(String[] args) {
Address address = new Address("liaoning", "dalian", "116081");
Student s = new Student("zhang", 20, address);
Student s2 = new Student(s);
System.out.println("s=" + s + "\ts2=" + s2);
System.out.println("s.name=" + s.getName() + "\ts2.name=" + s2.getName());
System.out.println("s.age=" + s.getAge() + "\ts2.age=" + s2.getAge());
System.out.println("s.adr=" + s.getAdd() + "\ts2.adr=" + s2.getAdd());
}
main()方法中代码“Student s2 = new Student(s)”的语义是:利用已创建好的学生对象s构建复制对象s2.在构造方法Student(Student s)中,首先进行了基本数据类型的值拷贝(name = s.getName();age=s.getAge()),然后进行了Address引用对象的地址拷贝(add = s.getAdd())。也就是说,s2对象的姓名、年龄与s的姓名、年龄是不同的内存地址空间;s2对象Address的引用对象与s的Address引用对象是一个相同的地址空间。
结果:
测试结果 | 说明 |
---|---|
s=com.itheima.yuan.Student@7852e922 s2=com.itheima.yuan.Student@4e25154f | s与s2对象地址不同 |
s.name=zhang s2.name=zhang | 姓名进行了复制 |
s.age=20 s2.age=20 | 年龄进行了复制 |
s.adr=com.itheima.yuan.Address@70dea4e s2.adr=com.itheima.yuan.Address@70dea4e | s和s2中的adr引用对象相同 |
2.深复制
Address.java
//其他代码同上
public Address(Address add) {
this.pro = add.getPro();
this.city = add.getCity();
this.zip = add.getZip();
}
Student.java
public Student(Student s) {
this.name = s.getName();
this.age = s.getAge();
this.add = new Address(s.getAdd());
}
测试类同上。
main()方法中代码"Student s2 = new Student(s)"的语义是:利用已创建好的学生对象s构建复制对象s2.在构造方法Student(Student s)中,首先进行了基本数据类型的值拷贝(name = s.getName();age = s.getAge()),然后进行了Address引用对象的内容拷贝(add = new Address(s.getAdd)),通过调用Address构造方法,建立了新的Address对象)。也就是说,s2对象的姓名、年龄、籍贯信息与s对象的姓名、年龄、籍贯信息时不同的内存地址空间。运行Test后,结果如下。
测试结果 | 说明 |
---|---|
s=com.itheima.yuan.Student@7852e922 s2=com.itheima.yuan.Student@4e25154f | s和s2对象地址不同 |
s.name=zhang s2.name=zhang | 姓名进行了复制 |
s.age=20 s2.age=20 | 年龄进行了复制 |
s.adr=com.itheima.yuan.Address@70dea4e s2.adr=com.itheima.yuan.Address@5c647e05 | s与s2中的adr引用对象的地址空间不相同 |
方法二:利用Cloneable接口方法
1.浅复制
Student.java
public class Student implements Cloneable {
//其他代码同上
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
Test.java
//其他代码同上
Student s2 = (Student)s.clone();
测试结果和构造函数方法浅复制结果一致
2.深复制
Address.java
public class Address implements Cloneable {
//其余代码同上
@Override
protected Address clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return (Address) super.clone();
}
}
Student.java
public class Student implements Cloneable {
//其余代码同上
@Override
protected Object clone() throws CloneNotSupportedException {
Student s = (Student) super.clone();
s.setAdd(add.clone());
return s;
}
}
方法三:利用Serializable序列化接口方法
1.深复制
Address.java
public class Address implements Serializable {
//其他代码同上
Student.java
public class Student implements Cloneable, Serializable {
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = null;
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
obj = ois.readObject();
} catch (Exception e) {
e.printStackTrace();
}
return obj;
}
//其他代码同上