詳解Java深拷貝,淺拷貝和Cloneable接口
1. Cloneable接口的介紹
Cloneable是標(biāo)記型的接口(空接口),它們內(nèi)部都沒(méi)有方法和屬性,實(shí)現(xiàn) Cloneable來(lái)表示該對(duì)象能被克隆,能使用Object.clone()方法。如果沒(méi)有實(shí)現(xiàn) Cloneable的類對(duì)象調(diào)用clone()就會(huì)拋出CloneNotSupportedException異常。
可以理解為Cloneable接口發(fā)揮的是標(biāo)記功能,自定義類型需要用戶自己標(biāo)記出哪些類是可以clone的,這個(gè)標(biāo)記就是去實(shí)現(xiàn)Cloneable接口,實(shí)現(xiàn)了Cloneable接口后就表明該類創(chuàng)建的對(duì)象可以被克隆。
而要想使一個(gè)類具備拷貝實(shí)例的功能,除了要實(shí)現(xiàn)Cloneable接口,還必須重寫(xiě)Object類的clone()方法。
可以看到Object類的clone()方法是被protected修飾的,所以需要在重寫(xiě)的clone()方法中通過(guò)super關(guān)鍵字去調(diào)用Object類中的clone()方法
2. 淺拷貝的介紹和實(shí)例
在拷貝一個(gè)對(duì)象時(shí),對(duì) 對(duì)象的基本數(shù)據(jù)類型的成員變量進(jìn)行拷貝,但對(duì)引用類型的成員變量只進(jìn)行引用的傳遞,并沒(méi)有創(chuàng)建一個(gè)新的對(duì)象,當(dāng)對(duì)引用類型的內(nèi)容修改會(huì)影響被拷貝的對(duì)象。簡(jiǎn)而言之:淺拷貝僅僅復(fù)制所拷貝的對(duì)象,而不復(fù)制它所引用的對(duì)象。
觀察下面的代碼,將Money類的實(shí)例作為了Person類的字段,new一個(gè)Person類的對(duì)象person1,將這個(gè)person1對(duì)象拷貝到person2中,這里的拷貝就是淺拷貝了,只是將person1對(duì)象的money引用拷貝到了person2,person1和person2中的momey指向的是同一個(gè)對(duì)象。
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("通過(guò)person2修改前的結(jié)果"); System.out.println(person1); System.out.println(person2); person2.money.m = 888; person2.id = 2; System.out.println("通過(guò)person2修改后的結(jié)果"); System.out.println(person1); System.out.println(person2); } }
執(zhí)行結(jié)果:
淺拷貝圖解:
3. 深拷貝的介紹和實(shí)例
在拷貝一個(gè)對(duì)象時(shí),除了對(duì)基本數(shù)據(jù)類型的成員變量進(jìn)行拷貝,對(duì)引用類型的成員變量進(jìn)行拷貝時(shí),創(chuàng)建一個(gè)新的對(duì)象來(lái)保存引用類型的成員變量。簡(jiǎn)而言之:深拷貝把要復(fù)制的對(duì)象所引用的對(duì)象都復(fù)制了一遍。
下面的代碼實(shí)現(xiàn)了深拷貝;實(shí)現(xiàn)person1對(duì)象的深拷貝,先用Person tmp引用來(lái)保存淺拷貝的結(jié)果,通過(guò)tmp引用找到money對(duì)象,再將money對(duì)象拷貝一份,然后賦值給tmp中的money,最后返回tmp即可。這樣就將money引用的對(duì)象也拷貝了一份,實(shí)現(xiàn)了深拷貝,此時(shí)person1和person2中的momey指向的是兩個(gè)不同的對(duì)象。
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("通過(guò)person2修改前的結(jié)果"); System.out.println(person1); System.out.println(person2); person2.money.m = 888; person2.id = 2; System.out.println("通過(guò)person2修改后的結(jié)果"); System.out.println(person1); System.out.println(person2); } }
執(zhí)行結(jié)果:
深拷貝圖解:
4. clone方法總結(jié)
java中clone方法是一個(gè)淺拷貝,引用類型依然在傳遞引用。我們可以通過(guò)繼續(xù)調(diào)用clone()方法,對(duì) 該對(duì)象的引用類型變量再實(shí)現(xiàn)一次clone()的方法來(lái)實(shí)現(xiàn)深拷貝。
到此這篇關(guān)于詳解Java深拷貝,淺拷貝和Cloneable接口的文章就介紹到這了,更多相關(guān)Java Cloneable接口內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
微服務(wù)SpringBoot整合Jasypt加密工具的場(chǎng)景分析
Jasypt是Java加密工具包,能支持對(duì)密碼的哈希加密,對(duì)文本和二進(jìn)制數(shù)據(jù)的對(duì)稱加解密,還能集成SpringBoot項(xiàng)目對(duì)配置文件中的密鑰進(jìn)行加密存儲(chǔ),這篇文章主要介紹了微服務(wù)SpringBoot整合Jasypt加密工具,需要的朋友可以參考下2022-10-10Java實(shí)現(xiàn)多個(gè)wav文件合成一個(gè)的方法示例
這篇文章主要介紹了Java實(shí)現(xiàn)多個(gè)wav文件合成一個(gè)的方法,涉及java文件流讀寫(xiě)、編碼轉(zhuǎn)換、解析等相關(guān)操作技巧,需要的朋友可以參考下2019-05-05Spring Boot 2.X優(yōu)雅的解決跨域問(wèn)題
這篇文章主要給大家介紹了關(guān)于Spring Boot 2.X如何優(yōu)雅的解決跨域問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot 2.X具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03Java中判斷對(duì)象是否相等的equals()方法使用教程
與==運(yùn)算符響應(yīng),equals()方法也是Java中對(duì)對(duì)象進(jìn)行比較的一大方式,要特別注意二者的不同點(diǎn),這個(gè)我們?cè)谙挛闹屑磳⒅v到,接下來(lái)我們就來(lái)看一下Java中判斷對(duì)象是否相等的equals()方法使用教程2016-05-05通過(guò)Java帶你了解網(wǎng)絡(luò)IO模型
這篇文章將通過(guò)Java帶大家了解網(wǎng)絡(luò)IO模型,包括BIO,NoBlockingIO,NIO(NewIO),AIO等做了詳細(xì)得介紹,感興趣的小伙伴可以參考閱讀本文2023-05-05Spring?Security?OAuth?Client配置加載源碼解析
這篇文章主要為大家介紹了Spring?Security?OAuth?Client配置加載源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07使用ScheduledThreadPoolExecutor踩過(guò)最痛的坑
這篇文章主要介紹了使用ScheduledThreadPoolExecutor踩過(guò)最痛的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08