ü 原型模式:用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象;
ü 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公司
---------------------------------