詳解Java深拷貝,淺拷貝和Cloneable接口
1. Cloneable接口的介紹
Cloneable是標(biāo)記型的接口(空接口),它們內(nèi)部都沒有方法和屬性,實(shí)現(xiàn) Cloneable來表示該對象能被克隆,能使用Object.clone()方法。如果沒有實(shí)現(xiàn) Cloneable的類對象調(diào)用clone()就會拋出CloneNotSupportedException異常。

可以理解為Cloneable接口發(fā)揮的是標(biāo)記功能,自定義類型需要用戶自己標(biāo)記出哪些類是可以clone的,這個(gè)標(biāo)記就是去實(shí)現(xiàn)Cloneable接口,實(shí)現(xiàn)了Cloneable接口后就表明該類創(chuàng)建的對象可以被克隆。
而要想使一個(gè)類具備拷貝實(shí)例的功能,除了要實(shí)現(xiàn)Cloneable接口,還必須重寫Object類的clone()方法。

可以看到Object類的clone()方法是被protected修飾的,所以需要在重寫的clone()方法中通過super關(guān)鍵字去調(diào)用Object類中的clone()方法

2. 淺拷貝的介紹和實(shí)例
在拷貝一個(gè)對象時(shí),對 對象的基本數(shù)據(jù)類型的成員變量進(jìn)行拷貝,但對引用類型的成員變量只進(jìn)行引用的傳遞,并沒有創(chuàng)建一個(gè)新的對象,當(dāng)對引用類型的內(nèi)容修改會影響被拷貝的對象。簡而言之:淺拷貝僅僅復(fù)制所拷貝的對象,而不復(fù)制它所引用的對象。
觀察下面的代碼,將Money類的實(shí)例作為了Person類的字段,new一個(gè)Person類的對象person1,將這個(gè)person1對象拷貝到person2中,這里的拷貝就是淺拷貝了,只是將person1對象的money引用拷貝到了person2,person1和person2中的momey指向的是同一個(gè)對象。
class Money {
public double m = 666;
}
class Person implements Cloneable{
int id;
public Money money = new Money();
public Person(int id) {
this.id = id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", money=" + money.m +
'}';
}
}
public class TestDemo3 {
public static void main(String[] args) throws CloneNotSupportedException {
Person person1 = new Person(1);
Person person2 = (Person) person1.clone();
System.out.println("通過person2修改前的結(jié)果");
System.out.println(person1);
System.out.println(person2);
person2.money.m = 888;
person2.id = 2;
System.out.println("通過person2修改后的結(jié)果");
System.out.println(person1);
System.out.println(person2);
}
}
執(zhí)行結(jié)果:

淺拷貝圖解:

3. 深拷貝的介紹和實(shí)例
在拷貝一個(gè)對象時(shí),除了對基本數(shù)據(jù)類型的成員變量進(jìn)行拷貝,對引用類型的成員變量進(jìn)行拷貝時(shí),創(chuàng)建一個(gè)新的對象來保存引用類型的成員變量。簡而言之:深拷貝把要復(fù)制的對象所引用的對象都復(fù)制了一遍。
下面的代碼實(shí)現(xiàn)了深拷貝;實(shí)現(xiàn)person1對象的深拷貝,先用Person tmp引用來保存淺拷貝的結(jié)果,通過tmp引用找到money對象,再將money對象拷貝一份,然后賦值給tmp中的money,最后返回tmp即可。這樣就將money引用的對象也拷貝了一份,實(shí)現(xiàn)了深拷貝,此時(shí)person1和person2中的momey指向的是兩個(gè)不同的對象。
class Money implements Cloneable{
public double m = 666;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable{
public int id;
public Money money = new Money();
public Person(int id) {
this.id = id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
//return super.clone();
Person tmp = (Person) super.clone();
tmp.money = (Money) this.money.clone();
return tmp;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", money=" + money.m +
'}';
}
}
public class Test2 {
public static void main(String[] args) throws CloneNotSupportedException{
Person person1 = new Person(1);
Person person2 = (Person) person1.clone();
System.out.println("通過person2修改前的結(jié)果");
System.out.println(person1);
System.out.println(person2);
person2.money.m = 888;
person2.id = 2;
System.out.println("通過person2修改后的結(jié)果");
System.out.println(person1);
System.out.println(person2);
}
}
執(zhí)行結(jié)果:

深拷貝圖解:

4. clone方法總結(jié)
java中clone方法是一個(gè)淺拷貝,引用類型依然在傳遞引用。我們可以通過繼續(xù)調(diào)用clone()方法,對 該對象的引用類型變量再實(shí)現(xiàn)一次clone()的方法來實(shí)現(xiàn)深拷貝。
到此這篇關(guān)于詳解Java深拷貝,淺拷貝和Cloneable接口的文章就介紹到這了,更多相關(guān)Java Cloneable接口內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springcloud-feign調(diào)用報(bào)錯(cuò)問題
這篇文章主要介紹了springcloud-feign調(diào)用報(bào)錯(cuò)問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08
WebUploader+SpringMVC實(shí)現(xiàn)文件上傳功能
WebUploader是由Baidu團(tuán)隊(duì)開發(fā)的一個(gè)簡單的以HTML5為主,F(xiàn)LASH為輔的現(xiàn)代文件上傳組件。這篇文章主要介紹了WebUploader+SpringMVC實(shí)現(xiàn)文件上傳功能,需要的朋友可以參考下2017-06-06
詳解SpringBoot+Mybatis實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換
這篇文章主要介紹了詳解SpringBoot+Mybatis實(shí)現(xiàn)動態(tài)數(shù)據(jù)源切換,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
hibernate一對多關(guān)聯(lián)映射學(xué)習(xí)小結(jié)
這篇文章主要介紹了hibernate一對多關(guān)聯(lián)映射學(xué)習(xí)小結(jié),需要的朋友可以參考下2017-09-09
Spring項(xiàng)目使用Maven和BCrypt實(shí)現(xiàn)修改密碼功能方式
在數(shù)字時(shí)代,信息安全尤其是密碼安全至關(guān)重要,本文通過實(shí)例探討如何在Spring項(xiàng)目中利用Maven和BCrypt實(shí)現(xiàn)一個(gè)安全的密碼修改功能,我們將從環(huán)境搭建到編寫核心業(yè)務(wù)邏輯,再到完成功能測試,確保每一步都遵循最佳安全實(shí)踐,通過本文,你將了解到密碼安全的重要性2024-10-10
Spring報(bào)錯(cuò):Error creating bean with name的問
這篇文章主要介紹了Spring報(bào)錯(cuò):Error creating bean with name的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
Java調(diào)用Python腳本實(shí)現(xiàn)HelloWorld的示例詳解
作為程序員,我們經(jīng)常會遇到需要在Java項(xiàng)目中調(diào)用Python腳本的場景,下面我們來看看如何從基礎(chǔ)到進(jìn)階,一步步實(shí)現(xiàn)Java與Python的"HelloWorld"交互吧2025-08-08
Java實(shí)現(xiàn)讀取不同格式的文件的示例詳解
在?Java?開發(fā)中,我們經(jīng)常需要讀取不同類型的文件,包括?Excel?表格文件、"doc"?等,本文將介紹如何使用?Java?讀取這些不同類型的文件,需要的可以參考下2024-01-01

