Java?Cloneable接口的深拷貝與淺拷貝詳解
Cloneable接口源碼
Cloneable接口:
實現(xiàn)此接口的類——可被推斷java.lang.Object的clone()方法可以被合法調(diào)用-以實現(xiàn)類實例:屬性到屬性的拷貝。
如果一個類未實現(xiàn)Cloneable接口,那么調(diào)用clone()方法時,會拋出CloneNotSupportedException異常。
通常,實現(xiàn)了Cloneable接口的子類,應(yīng)當(dāng)以public訪問權(quán)限重寫clone()方法(盡管java.Object類中的clone方法是protected類型的)
應(yīng)當(dāng)認(rèn)識到:Cloneable接口沒有包含clone()方法,因此,如果僅僅是implements了Cloneable接口,那么也是無法正??寺ο蟮?/p>
[原因:即使是反射性地調(diào)用了克隆方法,也不能保證它一定會成功]——個人理解就是:是否重寫Clone()方法、或者“淺拷貝與深拷貝”問題的存在所導(dǎo)致的。
class Pet implements Cloneable{
//properties
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Pet() {
}
public Pet(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pet pet = (Pet) o;
return Objects.equals(name, pet.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
// @Override
// public Pet clone() {
// try {
// return (Pet)super.clone();
// } catch (CloneNotSupportedException e) {
// e.printStackTrace();
// }
// return null;
// }
}
淺拷貝案例
Pet類定義
注意到:Pet類實現(xiàn)了Cloneable接口,但是沒有重寫Clone()方法(顯然:此時Pet類不具備對象克隆的能力)。
class Pet implements Cloneable{
//properties
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Pet() {
}
public Pet(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pet pet = (Pet) o;
return Objects.equals(name, pet.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
// @Override
// public Pet clone() {
// try {
// return (Pet)super.clone();
// } catch (CloneNotSupportedException e) {
// e.printStackTrace();
// }
// return null;
// }
}
Person類定義
注意到:Person類實現(xiàn)了Cloneable接口,也重寫Clone()方法。那么,是否Person類就具備了對象克隆的能力呢?(由于淺拷貝問題的存在,認(rèn)為這種對象克隆能力是不完整的、有缺陷的)。
class Pet implements Cloneable{
//properties
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Pet() {
}
public Pet(String name) {
this.name = name;
}
@Override
public String toString() {
return "Pet{" +
"name='" + name + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pet pet = (Pet) o;
return Objects.equals(name, pet.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
// @Override
// public Pet clone() {
// try {
// return (Pet)super.clone();
// } catch (CloneNotSupportedException e) {
// e.printStackTrace();
// }
// return null;
// }
}
淺拷貝問題-代碼測試
為什么說:此時Person類的對象克隆能力是不完整的、有缺陷的?因為此時,在通過Person對象調(diào)用clone()方法,克隆對象時,其成員屬性pet(Pet類的對象)值的克隆,僅僅是對堆區(qū)內(nèi)存地址的簡單拷貝。
即:說白了,Person對象和克隆出來的對象,其pet屬性值共享同一塊堆區(qū)內(nèi)存。——問題顯而易見:當(dāng)對克隆出來的對象的pet屬性進(jìn)行set操作時,顯然會影響到原始Person對象的pet屬性值。
代碼演示如下:
//methods
public static void main(String[] args) throws CloneNotSupportedException {
testPerson();
}
public static void testPerson() throws CloneNotSupportedException {
Person p=new Person("張三",14,new Pet("小黑"));
System.out.println(p);
Person clone = (Person)p.clone();
System.out.println(clone);
System.out.println(p.equals(clone));
System.out.println(p.getPet()==clone.getPet());
System.out.println("************");
clone.setAge(15);
System.out.println(p);
System.out.println(clone);
System.out.println(p.equals(clone));
System.out.println("************");
clone.getPet().setName("小黃");
System.out.println(p);
System.out.println(clone);
System.out.println(p.equals(clone));
System.out.println(p.getPet()==clone.getPet());
}

深拷貝案例
那么,如何實現(xiàn)深拷貝呢?關(guān)鍵就在上述案例中,被注釋的幾行代碼中。
Pet類重寫clone()方法

Person的clone()方法中調(diào)用Pet的clone方法

淺拷貝問題解決-深拷貝代碼測試
測試代碼不變,再次運行:

總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
Java實現(xiàn)的文本字符串操作工具類實例【數(shù)據(jù)替換,加密解密操作】
這篇文章主要介紹了Java實現(xiàn)的文本字符串操作工具類,可實現(xiàn)數(shù)據(jù)替換、加密解密等操作,涉及java字符串遍歷、編碼轉(zhuǎn)換、替換等相關(guān)操作技巧,需要的朋友可以參考下2017-10-10
SpringBoot中的@Conditional?注解的使用
@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進(jìn)行判斷,滿足條件的才給容器注冊Bean,本文主要介紹了SpringBoot中的@Conditional?注解的使用2024-01-01
mybatis參數(shù)String與Integer類型的判斷方式
這篇文章主要介紹了mybatis參數(shù)String與Integer類型的判斷方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03

