首先需要明白,淺拷貝和深拷貝都是針對(duì)一個(gè)已有對(duì)象的操作。那先來看看淺拷貝和深拷貝的概念:
對(duì)象拷貝有哪些
· 對(duì)象拷貝(Object Copy)就是將一個(gè)對(duì)象的屬性拷貝到另一個(gè)有著相同類類型的對(duì)象中去。在程序中拷貝對(duì)象是很常見的,主要是為了在新的上下文環(huán)境中復(fù)用對(duì)象的部分或全部數(shù)據(jù)。
· Java中有三種類型的對(duì)象拷貝:淺拷貝(Shallow Copy)、深拷貝(Deep Copy)、延遲拷貝(Lazy Copy)。
理解淺拷貝
淺拷貝是按位拷貝對(duì)象,它會(huì)創(chuàng)建一個(gè)新對(duì)象,這個(gè)對(duì)象有著原始對(duì)象屬性值的一份精確拷貝。如果屬性是基本類型,拷貝的就是基本類型的值;如果屬性是內(nèi)存地址(引用類型),拷貝的就是內(nèi)存地址 ,因此如果其中一個(gè)對(duì)象改變了這個(gè)地址,就會(huì)影響到另一個(gè)對(duì)象。
理解深拷貝
深拷貝會(huì)拷貝所有的屬性,并拷貝屬性指向的動(dòng)態(tài)分配的內(nèi)存。當(dāng)對(duì)象和它所引用的對(duì)象一起拷貝時(shí)即發(fā)生深拷貝。深拷貝相比于淺拷貝速度較慢并且花銷較大。
序列化進(jìn)行拷貝
可能你會(huì)問,序列化是屬于那種類型拷貝?答案是:通過序列化來實(shí)現(xiàn)深拷貝。可以思考一下,為何序列化對(duì)象要用深拷貝而不是用淺拷貝呢?
可以序列化是干什么的?它將整個(gè)對(duì)象圖寫入到一個(gè)持久化存儲(chǔ)文件中并且當(dāng)需要的時(shí)候把它讀取回來, 這意味著當(dāng)你需要把它讀取回來時(shí)你需要整個(gè)對(duì)象圖的一個(gè)拷貝。這就是當(dāng)你深拷貝一個(gè)對(duì)象時(shí)真正需要的東西。請(qǐng)注意,當(dāng)你通過序列化進(jìn)行深拷貝時(shí),必須確保對(duì)象圖中所有類都是可序列化的。
延遲拷貝
延遲拷貝是淺拷貝和深拷貝的一個(gè)組合,實(shí)際上很少會(huì)使用。
當(dāng)最開始拷貝一個(gè)對(duì)象時(shí),會(huì)使用速度較快的淺拷貝,還會(huì)使用一個(gè)計(jì)數(shù)器來記錄有多少對(duì)象共享這個(gè)數(shù)據(jù)。當(dāng)程序想要修改原始的對(duì)象時(shí),它會(huì)決定數(shù)據(jù)是否被共享(通過檢查計(jì)數(shù)器)并根據(jù)需要進(jìn)行深拷貝。
延遲拷貝從外面看起來就是深拷貝,但是只要有可能它就會(huì)利用淺拷貝的速度。當(dāng)原始對(duì)象中的引用不經(jīng)常改變的時(shí)候可以使用延遲拷貝。由于存在計(jì)數(shù)器,效率下降很高,但只是常量級(jí)的開銷。而且, 在某些情況下, 循環(huán)引用會(huì)導(dǎo)致一些問題。
如何選擇拷貝方式?
· 如果對(duì)象的屬性全是基本類型的,那么可以使用淺拷貝。
· 如果對(duì)象有引用屬性,那就要基于具體的需求來選擇淺拷貝還是深拷貝。
· 意思是如果對(duì)象引用任何時(shí)候都不會(huì)被改變,那么沒必要使用深拷貝,只需要使用淺拷貝就行了。如果對(duì)象引用經(jīng)常改變,那么就要使用深拷貝。沒有一成不變的規(guī)則,一切都取決于具體需求。
更多關(guān)于“Java培訓(xùn)”的問題,歡迎咨詢千鋒教育在線名師。千鋒已有十余年的培訓(xùn)經(jīng)驗(yàn),課程大綱更科學(xué)更專業(yè),有針對(duì)零基礎(chǔ)的就業(yè)班,有針對(duì)想提升技術(shù)的好程序員班,高品質(zhì)課程助理你實(shí)現(xiàn)java程序員夢(mèng)想。