Java 深拷貝和淺拷貝java
在淺拷貝中,若是原型對象的成員變量是基本類型時,將複製一份給克隆對象;若是原型對象的成員變量是引用類型,則將引用對象的地址複製一份給克隆對象,也就是說原型對象和克隆對象的成員變量指向相同的內存地址。ide
對應的深拷貝,若是時成員變量爲引用對象也複製一份給複製對象。測試
實現this
一、新建一個 Person 和 PersonId 類spa
public class Person implements Cloneable { private String name; private int age; private PersonId personId; public Person(String name, int age, int id) { this.name = name; this.age = age; this.personId = new PersonId(id); } public void setId(int id) { personId.setId(id); } public void setAge(int age) { this.age = age; } public Person clone() throws CloneNotSupportedException { Person cloned = (Person)super.clone(); return cloned; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", personId=" + personId + '}'; } }
class PersonId{ private int id; public PersonId(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "PersonId{" + "id=" + id + '}'; } }
二、使用 CloneDemo 類來測試淺拷貝code
public class CloneDemo { public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person("zhangsan",20,123); Person cloned = person.clone(); System.out.println("original: "+person); System.out.println("cloned: "+cloned); System.out.println("Modify Age and Id: "); cloned.setAge(55); cloned.setId(234); System.out.println("original: "+person); System.out.println("cloned: "+cloned); } }
三、輸出對象
能夠看到咱們修改了拷貝對象的年齡和ID,原始對象的年齡仍是20,原始對象的ID卻變成了咱們修改後的值,咱們並無對原始對象的ID進行修改,這裏說明淺拷貝對於對象僅僅是拷貝了一個對象的引用而已。blog
四、接下來咱們修改 Person 類的 clone() 方法,實現深拷貝。接口
public Person clone() throws CloneNotSupportedException { Person cloned = (Person)super.clone(); cloned.personId = personId.clone(); return cloned; }
五、爲了拷貝PersonId 的對象咱們須要PersonId 類實現 Cloneable 接口內存
class PersonId implements Cloneable{ private int id; public PersonId(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "PersonId{" + "id=" + id + '}'; } public PersonId clone() throws CloneNotSupportedException { return (PersonId)super.clone(); } }
六、再次運行 CloneDemo 輸出
能夠看到 原始對象的ID 值沒有被修改。
七、使用序列化實現深拷貝
import java.io.*; public class Person implements Cloneable, Serializable { private String name; private int age; private PersonId personId; public Person(String name, int age, int id) { this.name = name; this.age = age; this.personId = new PersonId(id); } public void setId(int id) { personId.setId(id); } public void setAge(int age) { this.age = age; } public Person clone() throws CloneNotSupportedException { try { ByteArrayOutputStream bout = new ByteArrayOutputStream(); try(ObjectOutputStream out = new ObjectOutputStream(bout)) { out.writeObject(this); } try(InputStream bin = new ByteArrayInputStream(bout.toByteArray())){ ObjectInputStream in = new ObjectInputStream(bin); return (Person)in.readObject(); } } catch (IOException | ClassNotFoundException e) { CloneNotSupportedException e2 = new CloneNotSupportedException(); e2.initCause(e); throw e2; } } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", personId=" + personId + '}'; } } class PersonId implements Cloneable,Serializable{ private int id; public PersonId(int id) { this.id = id; } public int getId() { return id; } public void setId(int id) { this.id = id; } @Override public String toString() { return "PersonId{" + "id=" + id + '}'; } public PersonId clone() throws CloneNotSupportedException { return (PersonId)super.clone(); } }
全部寫入流的對象都要實現 Serializable 接口。將 Person 對象寫入流中而後再從流中讀取出來實現深拷貝。
輸出:
總結
若要實現深拷貝,若是對象中引用了其餘對象,必須將引用的對象也克隆。