ü 原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象;
ü JAVA中可以通过实现Cloneable或者继承Cloneable类来实现对象的拷贝,然后就
可以调用clone()方法进行对象的复制了(直接调用会报CloneNotSupported
Exception)。但是此处需要注意的是clone()方法是由java.lang.Object类定义的,Object类是JAVA类层次的基类,因此所有类都会继承clone()方法,而不要误以为是Cloneabel接口(或Cloneable类)中有定义clone()方法;
ü 还需要注意的是clone()方法做的是浅拷贝,所做的操作是直接赋值字段的内容,即这个操作并不管字段对应的对象实例内容。假设现在有个字段对应到一个数组,当使用clone()方法进行复制时,复制的结果只对应到该数组的参照而已,并不会一个个复制该数组的元素。如果只做”浅拷贝”的clone无法满足你的要求,设计类的程序员也可以重写clone()方法,自行定义想要的”复制结果”;
ü 还需要注意的是:clone只会进行复制而已,并没有调用构造函数,如果该类在产生对象实例时需要做特殊的初始化,则应将处理操作语句放在clone方法之内;
实例:简历复制
Ø 文件:Resume.java
package com.yilong.prototype;
public class Resume implements Cloneable {
private String name;
private String sex;
private int age;
private String timearea;
private String company;
public Resume(String name) {
this.name = name;
}
public void setPersonalInfo(String sex, int age) {
this.sex = sex;
this.age = age;
}
public void setWrokExperience(String timearea, String company) {
this.timearea = timearea;
this.company = company;
}
public Resume resumeClone() {
Resume resume = null;
try {
resume = (Resume)clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return resume;
}
public void display() {
System.out.println("---------------------------------");
System.out.println("姓名:" + this.name);
System.out.println("性别:" + this.sex + " 年龄:" + this.age);
System.out.println("工作经历:" + this.timearea + " " + this.company);
System.out.println("---------------------------------");
}
}
Ø 测试文件Main.java
package com.yilong.prototype;
public class Main {
public static void main(String[] args) {
Resume resume1 = new Resume("逸龙");
resume1.setPersonalInfo("男", 22);
resume1.setWrokExperience("2001-2004", "XX公司");
Resume resume2 = resume1.resumeClone();
resume2.setPersonalInfo("男", 23);
resume2.setWrokExperience("2001-2005", "XXX公司");
resume1.display();
resume2.display();
}
}
打印结果:
---------------------------------
姓名:逸龙
性别:男 年龄:22
工作经历:2001-2004 XX公司
---------------------------------
---------------------------------
姓名:逸龙
性别:男 年龄:23
工作经历:2001-2005 XXX公司
---------------------------------
ü “浅复制”:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象;当我们需要把复制的对象所引用的对象都复制一遍的时候,就需要用到”深复制”:把引用对象的变量指向复制过的新对象,而不是原来的被引用的对象;下面是”浅复制”可能带来的不满足需求的情况:
但结果显示为:
实例:将上述的工作经历单独设置为一个类
Ø 文件WorkInfo.java
package com.yilong.prototype;
public class WorkInfo {
private String timeArea;
private String company;
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
public String getTimeArea() {
return timeArea;
}
public void setTimeArea(String timeArea) {
this.timeArea = timeArea;
}
}
Ø 文件Resume.java
package com.yilong.prototype;
public class Resume implements Cloneable {
private String name;
private String sex;
private int age;
private WorkInfo workInfo;
public Resume(String name) {
this.name = name;
}
public void setPersonalInfo(String sex, int age) {
this.sex = sex;
this.age = age;
}
public Resume resumeClone() {
Resume resume = null;
try {
resume = (Resume)clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return resume;
}
public void display() {
System.out.println("---------------------------------");
System.out.println("姓名:" + this.name);
System.out.println("性别:" + this.sex + " 年龄:" + this.age);
System.out.println("工作经历:" + this.workInfo.getTimeArea() + " " + this.workInfo.getCompany());
System.out.println("---------------------------------");
}
public WorkInfo getWorkInfo() {
return workInfo;
}
public void setWorkInfo(WorkInfo workInfo) {
this.workInfo = workInfo;
}
}
Ø 测试文件Main.java
package com.yilong.prototype;
public class Main {
public static void main(String[] args) {
Resume resume1 = new Resume("逸龙");
resume1.setPersonalInfo("男", 22);
WorkInfo workInfo = new WorkInfo();
workInfo.setTimeArea("2001-2003");
workInfo.setCompany("XX公司");
resume1.setWorkInfo(workInfo);
Resume resume2 = resume1.resumeClone();
resume2.setPersonalInfo("男", 23);
resume2.getWorkInfo().setTimeArea("2003-2004");
resume2.getWorkInfo().setCompany("XXVV公司");
resume1.display();
resume2.display();
}
}
打印结果:
---------------------------------
姓名:逸龙
性别:男 年龄:22
工作经历:2003-2004 XXVV公司
---------------------------------
---------------------------------
姓名:逸龙
性别:男 年龄:23
工作经历:2003-2004 XXVV公司
---------------------------------
结果说明:可见,打印的结果都是最后一次设置的工作经历的值,这主要是因为copy的是工作经历对象的引用,也就是说resume1和resume2里的workInfo都是指向同一个WorkInfo对象,而要达到预期的目标,主要是了解其中的原理,即在修改WorkInfo对象的值前必须新new一个新的WorkInfo对象,然后将其值设置为原来的WorkInfo里的值,这样再修改就会修改新分配的那块WorkInfo内存的值,具体可以将文件Resume.java里的resumeClone()函数修改为:
public Resume resumeClone() {
Resume resume = null;
try {
resume = (Resume)clone();
WorkInfo workInfo = new WorkInfo();
workInfo.setTimeArea(this.getWorkInfo().getTimeArea());
workInfo.setCompany(this.getWorkInfo().getCompany());
resume.setWorkInfo(workInfo);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return resume;
}
打印结果:
---------------------------------
姓名:逸龙
性别:男 年龄:22
工作经历:2001-2003 XX公司
---------------------------------
---------------------------------
姓名:逸龙
性别:男 年龄:23
工作经历:2003-2004 XXVV公司
---------------------------------