生活随笔
收集整理的這篇文章主要介紹了
我不知道的事——深克隆和浅克隆
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
??????
??????
推薦一部好電影《致命魔術》。(此處為植入廣告) ?????? 推薦理由:涉及人性。畫面不錯,劇情跌宕,亦魔亦幻(此處的”魔“為魔術的”魔“)。雖然女豬腳不盡如人意,但是男豬腳比較帥。而且看完后有利于理解克隆,當然理解了克隆也利于觀影! ?????? 首先,簡單客觀地解釋下幾個關鍵的名詞(我們約定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代碼 ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? ????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;?? ????????}??? ????}??? ?????? ????class ?Hero?implements ?Cloneable{?? ????????String?name;?? ????????int ?energy;??? ????????Sword?s;?? ????????public ?Hero(String?name,?int ?energy,?Sword?s){?? ????????????this .name?=?name;?? ????????????this .energy?=?energy;?? ????????????this .s?=?s;?? ????????}??? ?????????? ????????public ?void ?kill(){?? ????????????System.out.println("戰斗值為" ?+?energy?+?"的" ?+?name?+?"揮動著重為" ?? ????????????????????+?s.weight?+?"斤的" ?+?s.name?+?"要開殺戒了!" );?? ????????}??? ?????????? ????????? ? ?? ????????public ?Object?clone(){?? ????????????Hero?h?=?null ;?? ????????????try ?{?? ????????????????h?=?(Hero)super .clone();?? ????????????}?catch ?(CloneNotSupportedException?e)?{?? ????????????????e.printStackTrace();?? ????????????}??? ????????????return ?h;?? ????????}??? ????}??? ?????? ????public ?class ?ShallowClone{?? ????????? ? ? ?? ????????public ?static ?void ?main(String[]?args)?{?? ?????????????? ????????????Sword?s?=?new ?Sword("絕世好劍" ,?58 .3f);?? ?????????????? ????????????Hero?h1?=?new ?Hero("步驚云" ,?1000 ,?s);?? ????????????h1.kill();?? ?????????????? ????????????Hero?h2?=?(Hero)?h1.clone();?? ?????????????? ????????????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???????????????????+?"!" );?? ????????????}??? ????????}??? ????}???
??????
這段代碼的運行結果是什么呢?請看: ???? ?????? 戰斗值為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;?? ????????}??? ????????public ?Object?clone(){?? ????????????try ?{?? ????????????????return ?super .clone();?? ????????????}?catch ?(CloneNotSupportedException?e)?{?? ????????????????e.printStackTrace();?? ????????????}??? ????????????return ?null ;?? ????????}??? ????}??? ?? ????class ?Hero?implements ?Cloneable{?? ????????String?name;?? ????????int ?energy;??? ????????Sword?s;?? ????????public ?Hero(String?name,?int ?energy,?Sword?s){?? ????????????this .name?=?name;?? ????????????this .energy?=?energy;?? ????????????this .s?=?s;?? ????????}??? ????????public ?void ?kill(){?? ????????????System.out.println("戰斗值為" ?+?energy?+?"的" ?+?name?+?"揮動著??????????????????重為" ?+?s.weight?+?"斤的" ?+?s.name?+?"要開殺戒了!" );?? ????????}??? ????????? ? ?? ????????public ?Object?clone(){?? ????????????Hero?h?=?null ;?? ????????????try ?{?? ????????????????h?=?(Hero)super .clone();?? ????????????????h.s?=?(Sword)?s.clone();?? ????????????}?catch ?(CloneNotSupportedException?e)?{?? ????????????????e.printStackTrace();?? ????????????}??? ????????????return ?h;?? ????????}??? ????}??? ?? ????public ?class ?DeepClone{??? ????????? ? ? ?? ????????public ?static ?void ?main(String[]?args)?{?? ?????????????? ????????????Sword?s?=?new ?Sword("絕世好劍" ,?58 .3f);?? ?????????????? ????????????Hero?h1?=?new ?Hero("步驚云" ,?1000 ,?s);?? ????????????h1.kill();?? ?????????????? ????????????Hero?h2?=?(Hero)?h1.clone();?? ?????????????? ????????????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?+?"!" );?? ????????????}??? ????????}??? ????}???
??????
認真觀察就會發現,代碼的變動并不是很大,只是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 ?????? 最后,還有一件事,《致命魔術》真的不錯! ?????? 晚安!
總結
以上是生活随笔 為你收集整理的我不知道的事——深克隆和浅克隆 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。