最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入理解java中的拷貝機(jī)制

 更新時(shí)間:2017年02月15日 10:38:24   作者:QuinnNorris  
這篇文章主要給大家深入介紹了java中的拷貝機(jī)制,網(wǎng)上關(guān)于java中拷貝的文章也很多,但覺(jué)得有必要再深的介紹下java的拷貝機(jī)制,有需要的朋友可以參考學(xué)習(xí),下面來(lái)一起看看吧。

前言

眾所周知在Java中,拷貝分為深拷貝和淺拷貝兩種。java在公共超類(lèi)Object中實(shí)現(xiàn)了一種叫做clone的方法,這種方法clone出來(lái)的新對(duì)象為淺拷貝,而通過(guò)自己定義的clone方法為深拷貝。

(一)Object中clone方法

如果我們new出一個(gè)新對(duì)象,用一個(gè)聲明去引用它,之后又用另一個(gè)聲明去引用前一個(gè)聲明,那么最后的結(jié)果是:這兩個(gè)聲明的變量將指向同一個(gè)對(duì)象,一處被改全部被改。如果我們想創(chuàng)建一個(gè)對(duì)象的copy,這個(gè)copy和對(duì)象的各種屬性完全相同,而且修改這個(gè)copy和原對(duì)象毫無(wú)關(guān)系,那么這個(gè)時(shí)候我們就要用到clone方法。

package Clone;

import java.util.Date;

/**
 * 
 * @author QuinnNorris 
 * java中的兩種拷貝機(jī)制
 */
public class Clone {

 /**
 * @param args
 * @throws CloneNotSupportedException 
 */
 public static void main(String[] args) throws CloneNotSupportedException {
 // TODO Auto-generated method stub

 ClassA valA = new ClassA(1, "old", new Date());
 // 聲明一個(gè)新的ClassA對(duì)象,我們不需要太關(guān)注ClassA的功能
 ClassA valB = valA;
 // 將valA引用的對(duì)象賦給valB
 valA.setObject("new");
 // 更改valA中的值,此時(shí)valB也被更改了,因?yàn)関alA和valB指向同一個(gè)對(duì)象

 valB = valA.clone();//通過(guò)clone方法制造副本
 }
}

ClassA類(lèi)中關(guān)于clone方法的重寫(xiě)部分:

//需要實(shí)現(xiàn)Cloneable接口
public class ClassA implements Cloneable {

 public ClassA clone() throws CloneNotSupportedException {
 return (ClassA) super.clone();//調(diào)用父類(lèi)(Object)的clone方法
 }

}

1.如何使用Object中clone方法的

有人總結(jié)使用clone方法的四條法則,我們一起分享一下:

  1. 為了獲取對(duì)象的一份拷貝,我們可以利用Object類(lèi)的clone()方法。
  2. 在派生類(lèi)中覆蓋基類(lèi)的clone()方法,并聲明為public。
  3. 在派生類(lèi)的clone()方法中,調(diào)用super.clone() 
  4. 在派生類(lèi)中實(shí)現(xiàn)Cloneable接口。

2.protected修飾的clone方法

在java.lang.Object的中,他將clone方法設(shè)置為protected修飾,這是很特殊的一種情況。protected的作用域是:包可見(jiàn)+可繼承。之所以這樣設(shè)置,是因?yàn)檫@個(gè)方法要返回的是克隆出來(lái)的對(duì)象,即clone方法要去克隆的類(lèi)型是未知的,沒(méi)有辦法確定返回值的類(lèi)型,自然只能讓子孫后代來(lái)實(shí)現(xiàn)它重寫(xiě)它,為了能夠讓后代繼承而又不過(guò)與張開(kāi),設(shè)置為了protected類(lèi)型。

3.實(shí)現(xiàn)clone方法需要實(shí)現(xiàn)Cloneable接口

那么我們重寫(xiě)clone方法的時(shí)候?yàn)槭裁匆?shí)現(xiàn)Cloneable接口呢?事實(shí)上,Cloneable接口是java中的一個(gè)標(biāo)記接口,標(biāo)記接口是指那些沒(méi)有方法和屬性的接口,他們存在只是為了讓大家知道一些信息,而且在用:xxx instanceof Cloneable 的時(shí)候可以進(jìn)行判斷。Cloneable這個(gè)接口的出現(xiàn)就是為了讓設(shè)計(jì)者知道要進(jìn)行克隆處理了。如果一個(gè)對(duì)象需要克隆,但是沒(méi)有實(shí)現(xiàn)(實(shí)際上,這里的“實(shí)現(xiàn)”換成“寫(xiě)上”更準(zhǔn)確)Cloneable接口,那么會(huì)產(chǎn)生一個(gè)已檢驗(yàn)異常。

4.實(shí)現(xiàn)clone方法需要調(diào)用父類(lèi)的clone

我們?yōu)榱诉_(dá)到復(fù)制一個(gè)和調(diào)用方法的這個(gè)對(duì)象一模一樣的對(duì)象的目的,我們需要使用父類(lèi)的clone方法,父類(lèi)也以此類(lèi)推,知道達(dá)到了Object的clone方法,那么Object的clone方法有什么用呢?API中是這樣說(shuō)的:

protected Object clone( ) throws CloneNotSupportedException

創(chuàng)建并返回此對(duì)象的一個(gè)副本。

“副本”的準(zhǔn)確含義可能依賴(lài)于對(duì)象的類(lèi)。這樣做的目的是,對(duì)于任何對(duì)象 x,

表達(dá)式: x.clone() != x為 true,

表達(dá)式: x.clone().getClass() == x.getClass()也為 true,

但這些并非必須要滿足的要求。

一般情況下:

x.clone().equals(x)為 true,但這并非必須要滿足的要求。

按照慣例,返回的對(duì)象應(yīng)該通過(guò)調(diào)用 super.clone 獲得。

如果一個(gè)類(lèi)及其所有的超類(lèi)(Object 除外)都遵守此約定,則 x.clone().getClass() == x.getClass()

上面就是API中對(duì)clone的一部分基本講解。我們可以得出結(jié)論的是,只要合理的調(diào)用了spuer.clone( )它就會(huì)返回一個(gè)被克隆的對(duì)象。在運(yùn)行時(shí)刻,Object中的clone()識(shí)別出你要復(fù)制的是哪一個(gè)對(duì)象,然后為此對(duì)象分配空間,并進(jìn)行對(duì)象的復(fù)制,將原始對(duì)象的內(nèi)容一一復(fù)制到新對(duì)象的存儲(chǔ)空間中。在這個(gè)克隆對(duì)象中,所有的屬性都和被克隆的對(duì)象的屬性相同,而這些相同的屬性分為兩種:

第一種 : 八大原始類(lèi)型和不可變的對(duì)象(比如String)

第二種 : 其他類(lèi)對(duì)象

對(duì)于第一種,clone方法將他們的值設(shè)置為原對(duì)象的值,沒(méi)有任何問(wèn)題。對(duì)于第二種,clone方法只是簡(jiǎn)單的將復(fù)制的新對(duì)象的引用指向原對(duì)象指向的引用,第二種的類(lèi)對(duì)象會(huì)被兩個(gè)對(duì)象修改。那么這個(gè)時(shí)候就涉及一個(gè)深淺拷貝的概念了。

(二)淺拷貝

淺拷貝:被拷貝對(duì)象的所有變量都含有與原來(lái)的對(duì)象相同的值,而所有的對(duì)其他對(duì)象的引用仍然指向原來(lái)的對(duì)象。換言之,淺復(fù)制僅僅復(fù)制所考慮的對(duì)象,而不復(fù)制它所引用的對(duì)象。

比如舉個(gè)例子,一個(gè)類(lèi)A中有另外一個(gè)類(lèi)B類(lèi)型的變量。在A重寫(xiě)clone函數(shù)調(diào)用super.clone的時(shí)候,創(chuàng)建的新對(duì)象和原來(lái)對(duì)象中的類(lèi)B類(lèi)型的變量是同一個(gè),他們指向了同一個(gè)B的類(lèi)型變量。如果在A中對(duì)B的變量做了修改,在新的拷貝出來(lái)的對(duì)象中B的變量也會(huì)被同樣的修改。

請(qǐng)記住,直接調(diào)用super.clone實(shí)現(xiàn)的clone方法全部都是淺拷貝。

(三)深拷貝

深拷貝:被拷貝對(duì)象的所有變量都含有與原來(lái)的對(duì)象相同的值,除去那些引用其他對(duì)象的變量。那些引用其他對(duì)象的變量將指向被復(fù)制過(guò)的新對(duì)象,而不再是原有的那些被引用的對(duì)象。換言之,深復(fù)制把要復(fù)制的對(duì)象所引用的對(duì)象都復(fù)制了一遍。

通俗的說(shuō),如果說(shuō)淺拷貝,開(kāi)始的時(shí)候是兩條線,如果在最后有一個(gè)其他類(lèi)的變量,那么這兩條線最后會(huì)合二為一,共同指向這變量,都能對(duì)他進(jìn)行操作。深拷貝則是完完全全的兩條線,互不干涉,因?yàn)樗呀?jīng)把所有的內(nèi)部中的變量的對(duì)象全都復(fù)制一遍了。

深拷貝在代碼中,需要在clone方法中多書(shū)寫(xiě)調(diào)用這個(gè)類(lèi)中其他類(lèi)的變量的clone函數(shù)。

(四)串行化深拷貝

在框架中,有的時(shí)候我們發(fā)現(xiàn)其中并沒(méi)有重寫(xiě)clone方法,那么我們?cè)谛枰截愐粋€(gè)對(duì)象的時(shí)候是如何去操作的呢?答案是我們經(jīng)常會(huì)使用串行化方法,實(shí)現(xiàn)Serializable接口。

去尋找其他的方法來(lái)替代深拷貝也是無(wú)可奈何的事情,如果采用傳統(tǒng)的深拷貝,難道你拷貝一個(gè)對(duì)象的時(shí)候向其中追無(wú)數(shù)層來(lái)拷貝完所有的對(duì)象變量么?先不談這么做的時(shí)間消耗,僅僅是寫(xiě)這樣的代碼都會(huì)讓人望而生畏。串行化深拷貝就是這樣一個(gè)相對(duì)簡(jiǎn)單的方法。

把對(duì)象寫(xiě)到流里的過(guò)程是串行化(Serilization)過(guò)程,但是在Java程序師圈子里又非常形象地稱(chēng)為“冷凍”或者“腌咸菜(picking)”過(guò)程;而把對(duì)象從流中讀出來(lái)的并行化(Deserialization)過(guò)程則叫做 “解凍”或者“回鮮(depicking)”過(guò)程。應(yīng)當(dāng)指出的是,寫(xiě)在流里的是對(duì)象的一個(gè)拷貝,而原對(duì)象仍然存在于JVM里面,因此“腌成咸菜”的只是對(duì)象的一個(gè)拷貝,Java咸菜還可以回鮮。

上面是網(wǎng)上的專(zhuān)業(yè)解釋?zhuān)乙膊辉谶@里班門(mén)弄斧了。在Java語(yǔ)言里深復(fù)制一個(gè)對(duì)象,常常可以先使對(duì)象實(shí)現(xiàn)Serializable接口,然后把對(duì)象(實(shí)際上只是對(duì)象的一個(gè)拷貝)寫(xiě)到一個(gè)流里(腌成咸菜),再?gòu)牧骼镒x出來(lái)(把咸菜回鮮),便可以重建對(duì)象。

public Object deepClone() 
{ 
 //寫(xiě)入對(duì)象 
 ByteArrayOutoutStream bo=new ByteArrayOutputStream(); 
 ObjectOutputStream oo=new ObjectOutputStream(bo); 
 oo.writeObject(this); 
 //讀取對(duì)象
 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); 
 ObjectInputStream oi=new ObjectInputStream(bi); 
 return(oi.readObject()); 
}

雖然這種學(xué)院派的代碼看起來(lái)很復(fù)雜,其實(shí)只是把對(duì)象放到流里,再拿出來(lái)。相比較分析判斷無(wú)數(shù)的clone,這樣簡(jiǎn)直是再簡(jiǎn)單不過(guò)了。這樣做的前提是對(duì)象以及對(duì)象內(nèi)部所有引用到的對(duì)象都是可串行化的,否則,就需要仔細(xì)考察那些不可串行化的對(duì)象是否設(shè)成transient。

transient:一個(gè)對(duì)象只要實(shí)現(xiàn)了Serilizable接口,這個(gè)對(duì)象就可以被序列化(序列化是指將java代碼以字節(jié)序列的形式寫(xiě)出,即我們上面代碼前三行寫(xiě)入對(duì)象),Java的這種序列化模式為開(kāi)發(fā)者提供了很多便利,可以不必關(guān)系具體序列化的過(guò)程,只要這個(gè)類(lèi)實(shí)現(xiàn)了Serilizable接口,這個(gè)的所有屬性和方法都會(huì)自動(dòng)序列化。但是有種情況是有些屬性是不需要序列號(hào)的,所以就用到這個(gè)關(guān)鍵字。只需要實(shí)現(xiàn)Serilizable接口,將不需要序列化的屬性前添加關(guān)鍵字transient,序列化對(duì)象的時(shí)候,這個(gè)屬性就不會(huì)序列化到指定的目的地中。

總結(jié)

在實(shí)際的應(yīng)用中,深拷貝和淺拷貝只是兩個(gè)概念,不一定誰(shuí)比誰(shuí)好,要按照實(shí)際的工作來(lái)確定如何去拷貝一個(gè)對(duì)象。如果在數(shù)據(jù)庫(kù)操作方面,為了取出一張表時(shí)不涉及其他的表,肯定需要使用淺拷貝,而在框架的Serializable中,雖然耗時(shí),但是深拷貝是非常有必要的。

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。

相關(guān)文章

  • Idea中Java項(xiàng)目如何修改項(xiàng)目名

    Idea中Java項(xiàng)目如何修改項(xiàng)目名

    這篇文章主要介紹了Idea中Java項(xiàng)目如何修改項(xiàng)目名問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • Java實(shí)現(xiàn)簡(jiǎn)單控制臺(tái)版ATM系統(tǒng)

    Java實(shí)現(xiàn)簡(jiǎn)單控制臺(tái)版ATM系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)單控制臺(tái)版ATM系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • SpringSession會(huì)話管理之Redis與JDBC存儲(chǔ)實(shí)現(xiàn)方式

    SpringSession會(huì)話管理之Redis與JDBC存儲(chǔ)實(shí)現(xiàn)方式

    本文將詳細(xì)介紹Spring Session的核心概念、特性以及如何使用Redis和JDBC來(lái)實(shí)現(xiàn)會(huì)話存儲(chǔ),幫助開(kāi)發(fā)者構(gòu)建更加健壯和可擴(kuò)展的應(yīng)用系統(tǒng),希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • Spring Security 中細(xì)化權(quán)限粒度的方法

    Spring Security 中細(xì)化權(quán)限粒度的方法

    這篇文章主要介紹了Spring Security 中細(xì)化權(quán)限粒度的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • 從?PageHelper?到?MyBatis?Plugin執(zhí)行概要及實(shí)現(xiàn)原理

    從?PageHelper?到?MyBatis?Plugin執(zhí)行概要及實(shí)現(xiàn)原理

    這篇文章主要為大家介紹了從?PageHelper?到?MyBatis?Plugin執(zhí)行概要及實(shí)現(xiàn)原理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Java遍歷Map集合的方法(最新推薦)

    Java遍歷Map集合的方法(最新推薦)

    這篇文章主要介紹了Java遍歷Map集合的方法,遍歷map的key集合然后通過(guò)key獲取value,本文給大家講解的非常詳細(xì),需要的朋友可以參考下
    2024-05-05
  • SpringBoot整合jasypt實(shí)現(xiàn)敏感信息的加密詳解

    SpringBoot整合jasypt實(shí)現(xiàn)敏感信息的加密詳解

    一般公司的核心業(yè)務(wù)代碼中,都會(huì)存在與數(shù)據(jù)庫(kù)、第三方通信的secret key等敏感信息,如果以明文的方式存儲(chǔ),一旦泄露,那將會(huì)給公司帶來(lái)巨大的損失。本篇文章通過(guò)講解:Springboot集成Jasypt對(duì)項(xiàng)目敏感信息進(jìn)行加密,提高系統(tǒng)的安全性
    2022-09-09
  • 通過(guò)自定制LogManager實(shí)現(xiàn)程序完全自定義的logger

    通過(guò)自定制LogManager實(shí)現(xiàn)程序完全自定義的logger

    本章主要闡述怎么完全定制化LogManager來(lái)實(shí)現(xiàn)應(yīng)用程序完全自定制的logger,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-03-03
  • 總結(jié)Java中線程的狀態(tài)及多線程的實(shí)現(xiàn)方式

    總結(jié)Java中線程的狀態(tài)及多線程的實(shí)現(xiàn)方式

    Java中可以通過(guò)Thread類(lèi)和Runnable接口來(lái)創(chuàng)建多個(gè)線程,線程擁有五種狀態(tài),下面我們就來(lái)簡(jiǎn)單總結(jié)Java中線程的狀態(tài)及多線程的實(shí)現(xiàn)方式:
    2016-07-07
  • Java中的this和super實(shí)例淺析

    Java中的this和super實(shí)例淺析

    要說(shuō)this和super就不得不說(shuō)Java的封裝和繼承了。這篇文章主要介紹了Java中的this和super實(shí)例淺析,需要的朋友可以參考下
    2017-03-03

最新評(píng)論

保康县| 沈阳市| 遂川县| 崇文区| 周宁县| 通江县| 长海县| 荥阳市| 军事| 禹城市| 体育| 石城县| 寻乌县| 五原县| 太和县| 册亨县| 沙湾县| 肃宁县| 张家川| 察哈| 闽侯县| 辉县市| 年辖:市辖区| 连城县| 德安县| 余姚市| 五大连池市| 霞浦县| 绿春县| 监利县| 鄄城县| 贵德县| 平武县| 漳州市| 霍山县| 洛浦县| 舞钢市| 芜湖市| 汉中市| 安阳县| 福泉市|