Java中的拷貝操作可以大致分為深拷貝和淺拷貝,二者最主要的區(qū)別在于是否創(chuàng)建一個新的對象。淺拷貝會新建一個對象,但是其中的值類型和引用類型的地址都是復制原先對象中保存的引用類型的地址。而深拷貝則是創(chuàng)建一個全新的對象,其中包括引用類型的地址也是指向的新的地址。
下面我們舉個例子看看它們的具體使用區(qū)別
public class Person implements Cloneable{ private String name; private Address address; public Person(String name, Address address) { this.name = name; this.address = address; } @Override protected Person clone() throws CloneNotSupportedException { return (Person) super.clone(); } } public class Address { private String city; private String street; public Address(String city, String street) { this.city = city; this.street = street; } }
我們定義了Person類和Address類,Person類中含有Address類型的成員變量。然后我們分別進行淺拷貝和深拷貝。
@Test public void shallowClone() throws CloneNotSupportedException { Address address = new Address("北京", "中關村"); Person person1 = new Person("張三", address); Person person2 = person1.clone(); System.out.println(person1 == person2); //false System.out.println(person1.getAddress() == person2.getAddress()); //true } @Test public void deepClone() throws IOException, ClassNotFoundException { Address address = new Address("北京", "中關村"); Person person1 = new Person("張三", address); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(person1); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); Person person2 = (Person) objectInputStream.readObject(); System.out.println(person1 == person2); //false System.out.println(person1.getAddress() == person2.getAddress()); //false }
我們可以看到,使用淺拷貝clone方法返回的是不同的對象,但是內部的引用類型的地址還是相同的。而使用深拷貝使用序列化的方式將對象序列化到流中然后再反序列化回來,得到的對象包括引用對象的地址也是不同的,符合我們的深拷貝定義。