日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

我不知道的事——深克隆和浅克隆

發布時間:2023/12/18 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 我不知道的事——深克隆和浅克隆 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


??????
?????? 推薦一部好電影《致命魔術》。(此處為植入廣告)
?????? 推薦理由:涉及人性。畫面不錯,劇情跌宕,亦魔亦幻(此處的”魔“為魔術的”魔“)。雖然女豬腳不盡如人意,但是男豬腳比較帥。而且看完后有利于理解克隆,當然理解了克隆也利于觀影!

?????? 首先,簡單客觀地解釋下幾個關鍵的名詞(我們約定A表示原來的對象,P表示A引用的對象;AC表示克隆后的A對象):
?????? 淺克隆:復制克隆對象的基本信息及其對其他對象的引用。在改變AC對象的P對象時,那么也會改變A對象的P對象。
?????? 深克隆:深克隆也會復制對象的基本信息以及其對其他對象的引用,但是,改變AC對象的引用P對象時,不會引起A對象的P對象。

?????? 從前面淺克隆的定義上看,改變AC的P就能改變A的P,這樣顯得這種克隆更加像深克隆(都刨到別人祖墳了,夠深的!)。但是,換個角度來看,這種克隆只是淺顯的將一個對象拷貝出來了,并沒有真正的去對這個對象進行深入地剖析,即沒有剝離兩者之間的依賴,使得A和AC更像一個對象的不同命名,因此,反而顯得淺顯了。深克隆的技術含量也較之淺克隆高點。
?????? 為了方便理解,我將淺克隆形象化為一對連體雙胞胎,而將深克隆形象化為一對同卵雙胞胎;或者也可將淺克隆理解為鏡像,而深克隆則是復制了一個真正具有獨立行為能力的實體。
?????? 下面詳細對它們進行闡述:
?????? 克隆
?????? 實現克隆的類都必須實現Cloneable接口,而且一般需要重寫Object類里的clone()方法。我們首先看看Object類中對clone()方法的注釋與聲明:

Java代碼 ?
  • /**?
  • ?????*?Creates?and?returns?a?copy?of?this?object.??The?precise?meaning?
  • ?????*?of?"copy"?may?depend?on?the?class?of?the?object.?The?general?
  • ?????*?intent?is?that,?for?any?object?{@code?x},?the?expression:?
  • ?????*?<blockquote>?
  • ?????*?<pre>?
  • ?????*?x.clone()?!=?x</pre></blockquote>?
  • ?????*?will?be?true,?and?that?the?expression:?
  • ?????*?<blockquote>?
  • ?????*?<pre>?
  • ?????*?x.clone().getClass()?==?x.getClass()</pre></blockquote>?
  • ?????*?will?be?{@code?true},?but?these?are?not?absolute?requirements.?
  • ?????*?While?it?is?typically?the?case?that:?
  • ?????*?<blockquote>?
  • ?????*?<pre>?
  • ?????*?x.clone().equals(x)</pre></blockquote>?
  • ?????*?will?be?{@code?true},?this?is?not?an?absolute?requirement.?
  • ?????*?<p>?
  • ?????*?By?convention,?the?returned?object?should?be?obtained?by?calling?
  • ?????*?{@code?super.clone}.??If?a?class?and?all?of?its?superclasses?(except?
  • ?????*?{@code?Object})?obey?this?convention,?it?will?be?the?case?that?
  • ?????*?{@code?x.clone().getClass()?==?x.getClass()}.?
  • ?????*?<p>?
  • ?????*?By?convention,?the?object?returned?by?this?method?should?be?independent?
  • ?????*?of?this?object?(which?is?being?cloned).??To?achieve?this?independence,?
  • ?????*?it?may?be?necessary?to?modify?one?or?more?fields?of?the?object?returned?
  • ?????*?by?{@code?super.clone}?before?returning?it.??Typically,?this?means?
  • ?????*?copying?any?mutable?objects?that?comprise?the?internal?"deep?structure"?
  • ?????*?of?the?object?being?cloned?and?replacing?the?references?to?these?
  • ?????*?objects?with?references?to?the?copies.??If?a?class?contains?only?
  • ?????*?primitive?fields?or?references?to?immutable?objects,?then?it?is?usually?
  • ?????*?the?case?that?no?fields?in?the?object?returned?by?{@code?super.clone}?
  • ?????*?need?to?be?modified.?
  • ?????*?<p>?
  • ?????*?The?method?{@code?clone}?for?class?{@code?Object}?performs?a?
  • ?????*?specific?cloning?operation.?First,?if?the?class?of?this?object?does?
  • ?????*?not?implement?the?interface?{@code?Cloneable},?then?a?
  • ?????*?{@code?CloneNotSupportedException}?is?thrown.?Note?that?all?arrays?
  • ?????*?are?considered?to?implement?the?interface?{@code?Cloneable}?and?that?
  • ?????*?the?return?type?of?the?{@code?clone}?method?of?an?array?type?{@code?T[]}?
  • ?????*?is?{@code?T[]}?where?T?is?any?reference?or?primitive?type.?
  • ?????*?Otherwise,?this?method?creates?a?new?instance?of?the?class?of?this?
  • ?????*?object?and?initializes?all?its?fields?with?exactly?the?contents?of?
  • ?????*?the?corresponding?fields?of?this?object,?as?if?by?assignment;?the?
  • ?????*?contents?of?the?fields?are?not?themselves?cloned.?Thus,?this?method?
  • ?????*?performs?a?"shallow?copy"?of?this?object,?not?a?"deep?copy"?operation.?
  • ?????*?<p>?
  • ?????*?The?class?{@code?Object}?does?not?itself?implement?the?interface?
  • ?????*?{@code?Cloneable},?so?calling?the?{@code?clone}?method?on?an?object?
  • ?????*?whose?class?is?{@code?Object}?will?result?in?throwing?an?
  • ?????*?exception?at?run?time.?
  • ?????*?
  • ?????*?@return?????a?clone?of?this?instance.?
  • ?????*?@exception??CloneNotSupportedException??if?the?object's?class?does?not?
  • ?????*???????????????support?the?{@code?Cloneable}?interface.?Subclasses?
  • ?????*???????????????that?override?the?{@code?clone}?method?can?also?
  • ?????*???????????????throw?this?exception?to?indicate?that?an?instance?cannot?
  • ?????*???????????????be?cloned.?
  • ?????*?@see?java.lang.Cloneable?
  • ?????*/??
  • ????protected?native?Object?clone()?throws?CloneNotSupportedException;??

  • ?????? 雖然過長,但是我覺得還是很有必要看看的。從前面的注釋中可以看出:x.clone() != x 但是 x.clone().getClass() == x.getClass() 。這可以看成克隆的精確描述。從x.clone() != x 看,覺得這個鏡像也不簡單,鏡子里面的世界和鏡子外面的世界原來也不是同一個,開始有一點魔幻的味道了。注釋里還有一句話值得我們關注:Note that all arrays are considered to implement the interface? Cloneable and that the return type of the clone method of an array type T[] is T[] where T is any reference or primitive type.所有的數組都實現了Cloneable接口,返回的是一個數組類型。這個大家可以驗證一下,反正我驗證是有的。這段注釋里還有很多地方值得我們去研究(比如提到了深克隆和淺克隆),我都好不容易貼出來了,大家自己去看看吧!
    ?????? clone()方法會拋出CloneNotSupportedException,這是為什么呢?這是因為Object類沒有實現Cloneable接口。身為萬物之祖,Object也有很多不會的啊!

    ?????? 淺克隆
    ?????? 要想做到AC的屬性和A一樣其實并不難,最簡單的辦法就是AC = A;而且也能保證改變AC的P會引起A的P改變。這樣不就可以了嗎?為什么還要用克隆呢?你似乎忘了,在克隆里我們講過,AC和A需滿足兩個條件:x.clone() != x和x.clone().getClass() == x.getClass()。如果直接AC = A,很明顯AC == A返回的是true。至于具體原因就涉及到克隆的作用了,等會的克隆的用途會詳細說明。
    ?????? 淺克隆的實現并不難,下面看一個示例:

    Java代碼 ?
  • class?Sword{??
  • ????????String?name;??
  • ????????float?weight;??
  • ????????public?Sword(String?name,?float?weight){??
  • ????????????this.name?=?name;??
  • ????????????this.weight?=?weight;??
  • ????????}?//?end?constructor??
  • ????}?//?end?class?Sword??
  • ??????
  • ????class?Hero?implements?Cloneable{??
  • ????????String?name;??
  • ????????int?energy;?//?hero的戰斗值??
  • ????????Sword?s;??
  • ????????public?Hero(String?name,?int?energy,?Sword?s){??
  • ????????????this.name?=?name;??
  • ????????????this.energy?=?energy;??
  • ????????????this.s?=?s;??
  • ????????}?//?end?constructor??
  • ??????????
  • ????????public?void?kill(){??
  • ????????????System.out.println("戰斗值為"?+?energy?+?"的"?+?name?+?"揮動著重為"??
  • ????????????????????+?s.weight?+?"斤的"?+?s.name?+?"要開殺戒了!");??
  • ????????}?//?end?kill??
  • ??????????
  • ????????/**?
  • ?????????*?重寫Object的clone方法。?
  • ?????????*/??
  • ????????public?Object?clone(){??
  • ????????????Hero?h?=?null;??
  • ????????????try?{??
  • ????????????????h?=?(Hero)super.clone();??
  • ????????????}?catch?(CloneNotSupportedException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}?//?end?try-catch??
  • ????????????return?h;??
  • ????????}?//?end?clone??
  • ????}?//?end?class?Hero??
  • ??????
  • ????public?class?ShallowClone{??
  • ????????/**?
  • ?????????*?主函數。?
  • ?????????*?@param?args?
  • ?????????*/??
  • ????????public?static?void?main(String[]?args)?{??
  • ????????????//?聲明一個Sword對象??
  • ????????????Sword?s?=?new?Sword("絕世好劍",?58.3f);??
  • ????????????//?聲明一個Hero??
  • ????????????Hero?h1?=?new?Hero("步驚云",?1000,?s);??
  • ????????????h1.kill();??
  • ????????????//?克隆??
  • ????????????Hero?h2?=?(Hero)?h1.clone();??
  • ????????????//?改變h2的s的一些屬性??
  • ????????????h2.s.name?=?"草雉劍";??
  • ????????????h2.s.weight?=?23.4f;??
  • ????????????h1.kill();??
  • ????????if(?!(h1?==?h2)){??
  • ????????????System.out.println("從哲學的角度講:此時的"?+???
  • ????????????????h1.name?+?"已經不是從前的"?+?h1.name?+?"了!");??
  • ????????}else{??
  • ????????????System.out.println("娃哈哈,我"?+?h1.name?+?"還是"?+?h1.name???????????????????+?"!");??
  • ????????????}?//?end?if-else??
  • ????????}?//?end?main?????
  • ????}?//?end?class?ShallowClone??

  • ?????? 這段代碼的運行結果是什么呢?請看:
    ???? ?????? 戰斗值為1000的步驚云揮動著重為58.3斤的絕世好劍要開殺戒了!
    ?????????? 戰斗值為1000的步驚云揮動著重為23.4斤的草雉劍要開殺戒了!
    ?????????? 從哲學的角度講:此時的步驚云已經不是從前的步驚云了!
    ?????? 是的,正如我們所說的h1的s對象的name和weight也改變了。而且其實現也是很簡單。當然對這一塊比較熟悉的朋友會非常氣憤地指出,這里有一些基本的常識錯誤:絕世好劍和草雉劍根本就不是這個重量,步驚云也得不到草雉劍!但是,("made in China".equals("everything is possible")) == true(支持國產,再次植入廣告!)。好吧,我們回到淺克隆,這里實現淺克隆的代碼相當簡單,直接super.clone()就可以了。
    ?????? 網上有一種說法,說淺克隆是不正確的克隆。我覺得不管正不正確,當我們要克隆的對象只有基本數據類型和String等屬性時,直接淺克隆就可以了。運用之妙,存乎一心!

    ?????? 深克隆
    ?????? 前面講了,深克隆就是將克隆的對象和原來的對象獨立開來。那么怎么實現呢?
    ?????? 在上面的代碼上修改了一點:

    Java代碼 ?
  • class?Sword?implements?Cloneable{??
  • ????????String?name;??
  • ????????float?weight;??
  • ????????public?Sword(String?name,?float?weight){??
  • ????????????this.name?=?name;??
  • ????????????this.weight?=?weight;??
  • ????????}?//?end?constructor??
  • ????????public?Object?clone(){??
  • ????????????try?{??
  • ????????????????return?super.clone();??
  • ????????????}?catch?(CloneNotSupportedException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}?//?end?try-catch??
  • ????????????return?null;??
  • ????????}?//?end?clone??
  • ????}?//?end?class?Sword??
  • ??
  • ????class?Hero?implements?Cloneable{??
  • ????????String?name;??
  • ????????int?energy;?//?hero的戰斗值??
  • ????????Sword?s;??
  • ????????public?Hero(String?name,?int?energy,?Sword?s){??
  • ????????????this.name?=?name;??
  • ????????????this.energy?=?energy;??
  • ????????????this.s?=?s;??
  • ????????}?//?end?constructor??
  • ????????public?void?kill(){??
  • ????????????System.out.println("戰斗值為"?+?energy?+?"的"?+?name?+?"揮動著??????????????????重為"?+?s.weight?+?"斤的"?+?s.name?+?"要開殺戒了!");??
  • ????????}?//?end?kill??
  • ????????/**?
  • ?????????*?重寫Object的clone方法。?
  • ?????????*/??
  • ????????public?Object?clone(){??
  • ????????????Hero?h?=?null;??
  • ????????????try?{??
  • ????????????????h?=?(Hero)super.clone();??
  • ????????????????h.s?=?(Sword)?s.clone();??
  • ????????????}?catch?(CloneNotSupportedException?e)?{??
  • ????????????????e.printStackTrace();??
  • ????????????}?//?end?try-catch??
  • ????????????return?h;??
  • ????????}?//?end?clone??
  • ????}?//?end?class?Hero??
  • ??
  • ????public?class?DeepClone{???
  • ????????/**?
  • ?????????*?主函數。?
  • ????????*?@param?args?
  • ????????*/??
  • ????????public?static?void?main(String[]?args)?{??
  • ????????????//?聲明一個Sword對象??
  • ????????????Sword?s?=?new?Sword("絕世好劍",?58.3f);??
  • ????????????//?聲明一個Hero??
  • ????????????Hero?h1?=?new?Hero("步驚云",?1000,?s);??
  • ????????????h1.kill();??
  • ????????????//?克隆??
  • ????????????Hero?h2?=?(Hero)?h1.clone();??
  • ????????????//?改變h2的s的一些屬性??
  • ????????????h2.s.name?=?"草雉劍";??
  • ????????????h2.s.weight?=?23.4f;??
  • ????????????h1.kill();??
  • ????????????if(!?(h1?==?h2)){??
  • ????????????????System.out.println("從哲學的角度講:此時的"?+???
  • ????????????????????????h1.name?+?"已經不是從前的"?+?h1.name?+?"了!");??
  • ????????????}else{??
  • ????????????????System.out.println("娃哈哈,我"?+?h1.name?+?"還是"?+?h1.name?+?"!");??
  • ????????????}?//?end?if-else??
  • ????????}?//?end?main??
  • ????}?//?end?class?DeepClone??

  • ?????? 認真觀察就會發現,代碼的變動并不是很大,只是Sword類也實現了Cloneable接口,在Hero中也對hero對象的sword進行了克隆。這樣就實現了深克隆。那么這段代碼的結果是不是我們希望看到的呢:
    ?????????????? 戰斗值為1000的步驚云揮動著重為58.3斤的絕世好劍要開殺戒了!
    ?????????????? 戰斗值為1000的步驚云揮動著重為58.3斤的絕世好劍要開殺戒了!
    ?? ???????????? 從哲學的角度講:此時的步驚云已經不是從前的步驚云了!
    ?????? 看吧,h1并沒有因為克隆后的h2改變了s的name和weight而跟著發生了改變,圓滿完成了我們的預期目標。
    ?????? 關于深克隆還有另一種方式:使用Serializable。大家可以去關注一下,這里就不討論了。

    ?????? 克隆的用途
    ?????? 我們知道了深克隆和淺克隆,那么克隆到底有什么用呢?
    ?????? 答案很簡單:有需求就有市場。我們要克隆是因為我們需要一個和已知對象一樣的對象(這個我覺得看了《致命魔術》后肯定理解得更深)。當我們需要一個對象的副本但又不想影響原來的對象時,我們可以考慮使用克隆。
    ?????? 個人覺得克隆為程序員提供了對對象更加靈活的操縱力。我覺得大家在理解的基礎上然后提出自己的見解就可以了。

    ?????? 總結
    ?????? 最近看《Effective Java》,里面專門提到了:謹慎地覆蓋clone。而且里面也提到了用copy constructor(克隆構造器)或者copy factory(克隆工廠)更加地安全。網上有很多解說的,但是我覺得這個版本不錯,大家去看看吧:http://www.slideshare.net/fmshaon/effective-java-override-clone-method-judiciously

    ?????? 最后,還有一件事,《致命魔術》真的不錯!
    ?????? 晚安!

    總結

    以上是生活随笔為你收集整理的我不知道的事——深克隆和浅克隆的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。