Java中的對象克隆分為淺克隆和深克隆兩種方式。淺克隆是指在內存中復制一個對象,但是仍然指向相同的引用地址;而深克隆則是在內存中復制一個對象,并新建一個引用地址。
下面我們分別來看一下兩種克隆方式的具體實現:
// 淺克隆 public class User implements Cloneable { private String name; private Listhobbies; public User(String name, List hobbies) { this.name = name; this.hobbies = hobbies; } @Override public User clone() throws CloneNotSupportedException { return (User) super.clone(); } public static void main(String[] args) throws CloneNotSupportedException { List hobbies = new ArrayList<>(); hobbies.add("reading"); hobbies.add("writing"); User user = new User("Tom", hobbies); User cloneUser = user.clone(); System.out.println(user == cloneUser); System.out.println(user.getHobbies() == cloneUser.getHobbies()); } } // 輸出結果:true true
可以看出,淺克隆只是在內存中重新復制了一個對象,但是兩個對象的引用地址是相同的。所以在上面的代碼中,如果我們修改了cloneUser的hobbies屬性,會同時影響到user的hobbies屬性。
// 深克隆 public class User implements Serializable { private String name; private Listhobbies; public User(String name, List hobbies) { this.name = name; this.hobbies = hobbies; } public User clone() throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(this); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (User) ois.readObject(); } public static void main(String[] args) throws Exception { List hobbies = new ArrayList<>(); hobbies.add("reading"); hobbies.add("writing"); User user = new User("Tom", hobbies); User cloneUser = user.clone(); System.out.println(user == cloneUser); System.out.println(user.getHobbies() == cloneUser.getHobbies()); } } // 輸出結果:false false
通過上面的代碼可以看出,深克隆則是在內存中完全重新復制了一個對象,并新建一個引用地址,所以cloneUser與user是完全獨立的兩個對象。所以在上面的代碼中,如果我們修改了cloneUser的hobbies屬性,不會影響到user的hobbies屬性。
綜上所述,淺克隆只是復制了原有對象,而對于對象內的數組、引用等數據類型只會進行引用地址復制;而深克隆則是在內存中重新分配了空間,完全復制了原有對象。在實際開發中,如果我們需要獨立的、完整的副本對象,就需要使用深克隆。