Java淺拷貝深拷貝
淺拷貝和深拷貝涉及到了Object類中的clone()方法

實作淺拷貝
淺拷貝的實作需要類重寫clone()方法
淺拷貝會創建一個新物件,這個物件有著原始物件屬性值的一份精確拷貝
- 如果屬性是基本型別,拷貝的就是基本型別的值;
- 如果屬性是記憶體地址(參考型別),拷貝的就是記憶體地址 ,因此如果其中一個物件改變了這個地址,就會影響到另一個物件,導致兩個物件的參考不等,
實作淺拷貝很簡單只需要將類實作Cloneable介面然后重寫clone方法即可
class Person implements Cloneable {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* 重寫clone()方法
*
* @return
* @throws CloneNotSupportedException
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
測驗淺拷貝特性
public void testClone() throws CloneNotSupportedException {
Person person1 = new Person();
person1.setName("ccy");
person1.setAge(20);
Person person2 = (Person) person1.clone();
//查看淺拷貝效果
System.out.println(person1);
System.out.println(person2);
System.out.println(person1.getName() == person2.getName());
//驗證clone()的特性
System.out.println(person1.clone() != person1);
System.out.println(person1.clone().getClass() == person1.getClass());
//如果是基本型別淺拷貝直接賦值值,如果是參考型別淺拷貝指向其記憶體地址即共享記憶體地址
//改變person1的參考型別String屬性的值,參考發生改變
person1.setName("zfs");
System.out.println(person2.getName());
}

實作深拷貝
對于上述的問題雖然拷貝的兩個物件不同,但其內部的一些參考還是相同的,怎么樣絕對的拷貝這個物件,使這個物件完全獨立于原物件呢?就使用我們的深拷貝了,深拷貝:在對參考資料型別進行拷貝的時候,創建了一個新的物件,并且復制其內的成員變數,
在具體實作深拷貝上,這里提供兩個方式,重寫clone()方法和序列法,
重寫clone()方法
如果使用重寫clone()方法實作深拷貝,那么要將類中所有自定義參考變數的類也去實作Cloneable介面實作clone()方法,對于字符類可以創建一個新的字串實作拷貝,但是對于自定義類需要實作cloneable重寫clone,這樣做就太麻煩了所以我們使用序列化
序列化
序列化后將二進制位元組流內容寫到一個媒介(文本或位元組陣列),然后是從這個媒介讀取資料,原物件寫入這個媒介后拷貝給clone物件,原物件的修改不會影響clone物件,因為clone物件是從這個媒介讀取,
熟悉物件快取的知道我們經常將Java物件快取到Redis中,然后還可能從Redis中讀取生成Java物件,這就用到序列化和反序列化,一般可以將Java物件存盤為位元組流或者json串然后反序列化成Java物件,因為序列化會儲存物件的屬性但是不會也無法存盤物件在記憶體中地址相關資訊,所以在反序列化成Java物件時候會重新創建所有的參考物件,
在具體實作上,自定義的類需要實作Serializable介面
class Person implements Serializable {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
protected Person deepClone() throws Exception {
//序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (Person) ois.readObject();
}
}
測驗方法
public void testClone() throws Exception {
Person person1 = new Person();
person1.setName("ccy");
person1.setAge(20);
Person person2 = person1.deepClone();
System.out.println(person1.getName() == person2.getName());
}

可以看到兩個參考物件的地址并不同,成功實作了深拷貝
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/374747.html
標籤:java
