標籤:深拷貝 淺拷貝 clone
展示了淺拷貝:對於非基礎資料型別 (Elementary Data Type),clone過後,結果兩個指標指向了同一塊兒記憶體空間,所以僅僅是淺拷貝,這樣的話如果對一個對象進行操作,另一個內容也會變,這顯然是不合理的,應該每個對象分別儲存自己的資料。
所以我們要進行深拷貝!
淺拷貝和深拷貝例子:
import java.util.Vector;public class Student implements Cloneable{private int id;private String name;private Vector courses;public Student(){try{Thread.sleep(1000);System.out.println("Student Construnctor called");}catch(InterruptedException e){e.printStackTrace();}}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 Vector getCourses(){return courses;}public void setCourses(Vector courses){this.courses=courses;}public Student newInstance(){ //使用clone()建立對象,淺拷貝try{return (Student)this.clone();}catch(CloneNotSupportedException e){e.printStackTrace();}return null;}public Student deepClone(){//使用clone()建立對象,深拷貝try{Student cloning = (Student) super.clone();//Student cloning = (Strdent) this.clone();//和上一句話效果等價cloning.courses = new Vector();//關鍵點:非基礎資料型別 (Elementary Data Type)的空間需要自己新開闢一塊兒return cloning;}catch(CloneNotSupportedException e){e.printStackTrace();}return null;}}
import java.util.Vector;public class Test {public static void main(String[] args) {// TODO Auto-generated method stubStudent stu1 = null;shallowCopyDemo(stu1);System.out.println("----- ----- -----I'm cut-off rule----- ----- -----");deepCopyDemo(stu1);}public static void shallowCopyDemo(Student stu1) {stu1=new Student();Vector cs=new Vector();cs.add("Java");stu1.setId(1);stu1.setName("Tom");stu1.setCourses(cs);Student stu2=stu1.newInstance();stu2.setId(2);stu2.setName("Mary");stu2.getCourses().add("C#");System.out.println("stu1'name:"+stu1.getName());System.out.println("stu2'name:"+stu2.getName());System.out.println(stu1.getCourses()==stu2.getCourses());System.out.println(stu1.getName + "'s course: " + stu1.getCourses());System.out.println(stu2.getName + "'s course: " + stu2.getCourses());}public static void deepCopyDemo(Student stu1) {stu1=new Student();Vector cs=new Vector();cs.add("Java");stu1.setId(1);stu1.setName("Tom");stu1.setCourses(cs);Student stu2=stu1.deepClone();stu2.setId(2);stu2.setName("Mary");stu2.getCourses().add("C#");System.out.println("stu1'name:"+stu1.getName());System.out.println("stu2'name:"+stu2.getName());System.out.println(stu1.getCourses()==stu2.getCourses());System.out.println(stu1.getName + "'s course: " + stu1.getCourses());System.out.println(stu2.getName + "'s course: " + stu2.getCourses());}}
輸出結果:
Student Construnctor called
stu1‘name:Tom
stu2‘name:Mary
true
Tom‘s course: [Java, C#]
Mary‘s course: [Java, C#]
----- ----- -----I‘m cut-off rule----- ----- -----
Student Construnctor called
stu1‘name:Tom
stu2‘name:Mary
false
Tom‘s course: [Java]
Mary‘s course: [C#]
由結果可知,第一種調用淺拷貝導致對Mary添加課程C#的時候,Tom的課程中竟然也有了C#,而且Mary的課程中也有Tom的Java,且stu1.getCourses()==stu2.getCourses()返回的是“true”,說明二者的course屬性指向的就是同一塊兒記憶體;而在第二種情況中,我們為copy出來的Mary的course新開闢了一塊兒空間cloning.courses = new Vector(),所以Tom和Mary操控的是不同的Vector記憶體,兩者自然就不一樣了。
在上例中,深拷貝deepClone()和淺拷貝newInstance()函數都是我們自己寫的,所以deepClone()的Student cloning = (Student) super.clone()和Student cloning = (Strdent) this.clone()都是可行的。除此之外,我們也可以直接覆寫本類的clone()函數這樣的話就只能使用Student cloning = (Student) super.clone()了,覆寫的代碼如下:
public Object clone(){//覆寫clone(),深拷貝try{Student cloning = (Student) super.clone();cloning.courses = new Vector();//關鍵點:非基礎資料型別 (Elementary Data Type)的空間需要自己新開闢一塊兒return cloning;}catch(CloneNotSupportedException e){e.printStackTrace();}return null;}這裡不能使用Student cloning = (Strdent) this.clone()的原因是我們正在覆寫本類的clone()方法,如果再調用本類的函數,即:this.clone(),就相當於無線遞迴無限死迴圈了,最終肯定會崩潰的。所以這裡我們只能調用父類的函數,即:super.clone()。
所以,要麼自己給自己的深拷貝函數起一個名字,要麼覆寫本類的clone()方法,自己選一個就好,但兩者的關鍵都在於——對於非基礎資料型別 (Elementary Data Type),要重新new一塊兒空間。
Java中的clone() 深拷貝 淺拷貝