Java的淺度克隆和深度克隆
阿新 • • 發佈:2019-02-10
前言:
protected native Object clone() throws CloneNotSupportedException方法由protected修飾,只能由子類重寫和呼叫,而且為本地方法。
Object提供clone方法,生成物件的一個副本,來實現物件的一次淺度克隆。但是物件的引用型別不會拷貝一份,引用地址與原物件相同。
實現物件的克隆需要實現Cloneable介面,重寫clone方法,通過super.clone()呼叫Object類的clone方法得到當前物件的副本,並放回該副本。
淺度克隆與深度克隆的區別:
淺度克隆:基本型別都會拷貝一份,引用型別引用地址不變,還是同一個物件。
深度克隆:基本型別和引用型別都會拷貝一份,完完全全的是不同的兩份,引用地址不一樣。
下面結合一個具體的例子:(兩者結合)
定義person類:(實現了Cloneable介面)
定義Student類(實現Cloneable介面)class Person implements Cloneable{ int id; public Person(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
public class Student implements Cloneable{ private int age; //基本型別 private String name; //引用型別,未實現自己的深度拷貝 private Person person; //引用型別,Person類實現了Cloneable介面,深度拷貝 public Student(int age, String name, Person person) { this.age = age; this.name = name; this.person = person; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } @Override protected Object clone() throws CloneNotSupportedException { Student student = (Student) super.clone(); Person person = (Person) student.getPerson().clone(); //這個為重點,把student裡面的引用型別person深度克隆 student.setPerson(person); return student; } public static void main(String[] args) throws Exception{ Person person = new Person(2); Student student1 = new Student(10,"wqh", person); Student student2 = (Student) student1.clone(); System.out.println(student1 == student2); //false System.out.println(student1.getName()==student2.getName()); //true System.out.println(student1.getPerson() == student2.getPerson()); //false } }
輸出結果:
false
true
false
分析:
Student中有兩個引用型別:String和Person,在Person中實現了clone介面,在Student的clone方法中我們對person屬性也進行了一次深度克隆,這樣對student1拷貝成student2後,各自的person屬性是單獨的兩份,引用地址不一樣,所以為false,但是string屬性是同一份,故為true。綜述,對student2而言,這是一次不徹底的深度克隆,因為部分引用屬性沒有進行深度克隆。
畫個圖來明瞭下:
student1和student2對應於堆中的同一個name,不同的person。