日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
如何理解Java的淺拷貝和深拷貝

這篇文章主要介紹“如何理解Java的淺拷貝和深拷貝”,在日常操作中,相信很多人在如何理解Java的淺拷貝和深拷貝問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何理解Java的淺拷貝和深拷貝”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

創(chuàng)新互聯(lián)公司2013年開創(chuàng)至今,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項(xiàng)目網(wǎng)站制作、成都網(wǎng)站制作網(wǎng)站策劃,項(xiàng)目實(shí)施與項(xiàng)目整合能力。我們以讓每一個(gè)夢想脫穎而出為使命,1280元莫力達(dá)做網(wǎng)站,已為上家服務(wù),為莫力達(dá)各地企業(yè)和個(gè)人服務(wù),聯(lián)系電話:18982081108

1.創(chuàng)建對象的5種方式

  • 通過 new 關(guān)鍵字

這是最常用的一種方式,通過 new 關(guān)鍵字調(diào)用類的有參或無參構(gòu)造方法來創(chuàng)建對象。

比如 Object obj = new Object();

  • 通過 Class 類的 newInstance() 方法

這種默認(rèn)是調(diào)用類的無參構(gòu)造方法創(chuàng)建對象。

比如 Person p2 = (Person) Class.forName("com.ys.test.Person").newInstance();

  • 通過 Constructor 類的 newInstance 方法

這和第二種方法類似,都是通過反射來實(shí)現(xiàn)。通過 java.lang.relect.Constructor 類的 newInstance() 方法指定某個(gè)構(gòu)造器來創(chuàng)建對象。

Person p3 = (Person) Person.class.getConstructors()[0].newInstance();

實(shí)際上第二種方法利用 Class 的 newInstance() 方法創(chuàng)建對象,其內(nèi)部調(diào)用還是 Constructor 的 newInstance() 方法。

  • 利用 Clone 方法

Clone 是 Object 類中的一個(gè)方法,通過 對象A.clone() 方法會(huì)創(chuàng)建一個(gè)內(nèi)容和對象 A 一模一樣的對象 B,clone 克隆,顧名思義就是創(chuàng)建一個(gè)一模一樣的對象出來。

Person p4 = (Person) p3.clone();

  • 反序列化

序列化是把堆內(nèi)存中的 Java 對象數(shù)據(jù),通過某種方式把對象存儲(chǔ)到磁盤文件中或者傳遞給其他網(wǎng)絡(luò)節(jié)點(diǎn)(在網(wǎng)絡(luò)上傳輸)。而反序列化則是把磁盤文件中的對象數(shù)據(jù)或者把網(wǎng)絡(luò)節(jié)點(diǎn)上的對象數(shù)據(jù),恢復(fù)成Java對象模型的過程。

2. Clone方法

在 Object.class 類中,源碼為:

protected native Object clone() throws CloneNotSupportedException;

這是一個(gè)用 native 關(guān)鍵字修飾的方法,不理解也沒關(guān)系,只需要知道用 native 修飾的方法就是告訴操作系統(tǒng),這個(gè)方法我不實(shí)現(xiàn)了,讓操作系統(tǒng)去實(shí)現(xiàn)。具體怎么實(shí)現(xiàn)我們不需要了解,只需要知道 clone方法的作用就是復(fù)制對象,產(chǎn)生一個(gè)新的對象。那么這個(gè)新的對象和原對象是什么關(guān)系呢?

3. 基本類型和引用類型

在 Java 中數(shù)據(jù)類型可以分為兩大類:基本類型和引用類型。

基本類型也稱為值類型,分別是字符類型 char,布爾類型 boolean以及數(shù)值類型 byte、short、int、long、float、double。

引用類型則包括類、接口、數(shù)組、枚舉等。

Java 將內(nèi)存空間分為堆和棧。基本類型直接在棧中存儲(chǔ)數(shù)值,而引用類型是將引用放在棧中,實(shí)際存儲(chǔ)的值是放在堆中,通過棧中的引用指向堆中存放的數(shù)據(jù)。

如何理解Java的淺拷貝和深拷貝

上圖定義的 a 和 b 都是基本類型,其值是直接存放在棧中的;而 c 和 d 是 String 聲明的,這是一個(gè)引用類型,引用地址是存放在 棧中,然后指向堆的內(nèi)存空間。

下面 d = c;這條語句表示將 c 的引用賦值給 d,那么 c 和 d 將指向同一塊堆內(nèi)存空間。

4. 淺拷貝

在講解淺拷貝之前,我們用一段代碼來實(shí)現(xiàn)它。

如何理解Java的淺拷貝和深拷貝

如何理解Java的淺拷貝和深拷貝

如何理解Java的淺拷貝和深拷貝

上面的代碼是一個(gè)我們要進(jìn)行賦值的原始類 Person。下面我們產(chǎn)生一個(gè) Person 對象,并調(diào)用其 clone 方法復(fù)制一個(gè)新的對象。

注意:調(diào)用對象的 clone 方法,必須要讓類實(shí)現(xiàn) Cloneable 接口,并且覆寫 clone 方法。

如何理解Java的淺拷貝和深拷貝

如何理解Java的淺拷貝和深拷貝

首先看原始類 Person 實(shí)現(xiàn) Cloneable 接口,并且覆寫 clone 方法,它還有三個(gè)屬性,一個(gè)引用類型 String定義的 pname,一個(gè)基本類型 int定義的 page,還有一個(gè)引用類型 Address ,這是一個(gè)自定義類,這個(gè)類也包含兩個(gè)屬性 pprovices 和 city 。

接著看測試內(nèi)容,首先我們創(chuàng)建一個(gè)Person 類的對象 p1,其pname 為zhangsan,page為21,地址類 Address 兩個(gè)屬性為 湖北省和武漢市。接著我們調(diào)用 clone() 方法復(fù)制另一個(gè)對象 p2,接著打印這兩個(gè)對象的內(nèi)容。

從第 1 行和第 3 行打印結(jié)果:

p1:com.bowen.demo.demo008.method1.Person@5dfe23e8  
p2:com.bowen.demo.demo008.method1.Person@583fb274

可以看出這是兩個(gè)不同的對象。

從第 5 行和第 6 行打印的對象內(nèi)容看,原對象 p1 和克隆出來的對象 p2 內(nèi)容完全相同。

代碼中我們只是更改了克隆對象 p2 的屬性 Address 為湖北省荊州市(原對象 p1 是湖北省武漢市) ,但是從第 7 行和第 8 行打印結(jié)果來看,原對象 p1 和克隆對象 p2 的 Address 屬性都被修改了。

也就是說對象 Person 的屬性 Address,經(jīng)過 clone 之后,其實(shí)只是復(fù)制了其引用,他們指向的還是同一塊堆內(nèi)存空間,當(dāng)修改其中一個(gè)對象的屬性 Address,另一個(gè)也會(huì)跟著變化。

如何理解Java的淺拷貝和深拷貝

淺拷貝:創(chuàng)建一個(gè)新對象,然后將當(dāng)前對象的非靜態(tài)字段復(fù)制到該新對象,如果字段是值類型的,那么對該字段執(zhí)行復(fù)制;如果該字段是引用類型的話,則復(fù)制引用但不復(fù)制引用的對象。因此,原始對象及其副本引用同一個(gè)對象。

5. 深拷貝

弄清楚了淺拷貝,那么深拷貝就很容易理解了。

深拷貝:創(chuàng)建一個(gè)新對象,然后將當(dāng)前對象的非靜態(tài)字段復(fù)制到該新對象,無論該字段是值類型的還是引用類型,都復(fù)制獨(dú)立的一份。當(dāng)你修改其中一個(gè)對象的任何內(nèi)容時(shí),都不會(huì)影響另一個(gè)對象的內(nèi)容。

如何理解Java的淺拷貝和深拷貝

那么該如何實(shí)現(xiàn)深拷貝呢?Object 類提供的 clone 是只能實(shí)現(xiàn)淺拷貝的。

6. 如何實(shí)現(xiàn)深拷貝?

深拷貝的原理我們知道了,就是要讓原始對象和克隆之后的對象所具有的引用類型屬性不是指向同一塊堆內(nèi)存,這里有兩種實(shí)現(xiàn)思路。

方法一:讓每個(gè)引用類型屬性內(nèi)部都重寫clone() 方法

既然引用類型不能實(shí)現(xiàn)深拷貝,那么我們將每個(gè)引用類型都拆分為基本類型,分別進(jìn)行淺拷貝。比如上面的例子,Person 類有一個(gè)引用類型 Address(其實(shí)String 也是引用類型,但是String類型有點(diǎn)特殊,后面會(huì)詳細(xì)講解),我們在 Address 類內(nèi)部也重寫 clone 方法。如下:

Address.class:

如何理解Java的淺拷貝和深拷貝

Person.class 的 clone() 方法:

@Override
	protected Object clone() throws CloneNotSupportedException {
		Person p = (Person) super.clone();
		p.address = (Address) address.clone();
		return p;
	}

測試還是和上面一樣,我們會(huì)發(fā)現(xiàn)更改了p2對象的Address屬性,p1 對象的 Address 屬性并沒有變化。

如何理解Java的淺拷貝和深拷貝

但是這種做法有個(gè)弊端,這里我們Person 類只有一個(gè) Address 引用類型,而 Address 類沒有,所以我們只用重寫 Address 類的clone 方法,但是如果 Address 類也存在一個(gè)引用類型,那么我們也要重寫其clone 方法,這樣下去,有多少個(gè)引用類型,我們就要重寫多少次,如果存在很多引用類型,那么代碼量顯然會(huì)很大,所以這種方法不太合適。

方法二:利用序列化

序列化是將對象寫到流中便于傳輸,而反序列化則是把對象從流中讀取出來。這里寫到流中的對象則是原始對象的一個(gè)拷貝,因?yàn)樵紝ο筮€存在 JVM 中,所以我們可以利用對象的序列化產(chǎn)生克隆對象,然后通過反序列化獲取這個(gè)對象。

注意每個(gè)需要序列化的類都要實(shí)現(xiàn) Serializable 接口,如果有某個(gè)屬性不需要序列化,可以將其聲明為 transient,即將其排除在克隆屬性之外。

如何理解Java的淺拷貝和深拷貝

因?yàn)樾蛄谢a(chǎn)生的是兩個(gè)完全獨(dú)立的對象,所以無論嵌套多少個(gè)引用類型,序列化都是能實(shí)現(xiàn)深拷貝的。

到此,關(guān)于“如何理解Java的淺拷貝和深拷貝”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!


網(wǎng)站欄目:如何理解Java的淺拷貝和深拷貝
文章地址:http://www.dlmjj.cn/article/jieiod.html