JAVA 對象拷貝

          為什么需要有對象拷貝?

          對象拷貝相對的自然是引用拷貝。java初學者經常會問,我這個方法要改變一個對象的屬性,可以把參數傳進去了,為什么沒有改變了?

          ——基本數據類型傳值,而對象傳引用或引用的拷貝。

          而有時候我們要獲取到一個當前狀態的對象復制品,他們是兩個獨立對象。不再是引用或者引用拷貝(實質都是指向對象本身)。就是說a是b的拷貝,b發生變化的時候,不要影響a。


          對象拷貝有淺拷貝和深度拷貝兩種。

          1)淺拷貝

          淺拷貝是指對象中基本數據類型得到拷貝,而引用數據類型并未拷貝。
          提到拷貝自然和clone聯系起來了,所有具有clone功能的類都有一個特性,那就是它直接或間接地實現了Cloneable接口。
          否則,我們在嘗試調用clone()方法時,將會觸發CloneNotSupportedException異常。
          eg:

          ?1 public ? class ?DOG? implements ?Cloneable
          ?2 {
          ?3 ???? public ?DOG(String?name,? int ?age)
          ?4 ???? {
          ?5 ???????? this .name? = ?name;
          ?6 ???????? this .age? = ?age;
          ?7 ????}

          ?8
          ?9 ???? public ?String?getName()
          10 ???? {
          11 ???????? return ? this .name;
          12 ????}

          13
          14 ???? public ? int ?getAge()
          15 ???? {
          16 ???????? return ? this .age;
          17 ????}

          18
          19 ???? public ?Object?clone()
          20 ???? {
          21 ???????? try
          22 ???????? {
          23 ???????????? return ? super .clone();
          24
          25 ????????}
          ? catch ?(CloneNotSupportedException?e)
          26 ???????? {
          27 ???????????? return ? null ;
          28 ????????}

          29 ????}

          30
          31 ???? public ?String?name;
          32
          33 ???? private ? int ?age;
          34
          35 ???? // test
          36 ???? public ? static ? void ?main(String[]?args)
          37 ???? {
          38 ????????DOG?dog1? = ? new ?DOG( " xiaogou " ,? 2 );
          39 ????????DOG?dog2? = ?(DOG)?dog1.clone();
          40 ????????dog1.name? = ? " dagou " ;
          41 ????????System.out.println(dog2.getName());
          42 ????????System.out.println(dog2.getAge());
          43 ????????System.out.println(dog1.getName());
          44 ????????System.out.println(dog1.getAge());
          45
          46 ????}

          47
          48 }

          49



          運行結果:

          xiaogou
          2
          dagou
          2

          2)深度拷貝

          相對淺拷貝。實現對象中基本數據類型和引用數據類型的拷貝。

          請先看下面代碼:

          ?

          ?1 class ?AAA
          ?2 {
          ?3 ???? public ?AAA(String?name)
          ?4 ???? {
          ?5 ???????? this .name? = ?name;
          ?6 ????}

          ?7
          ?8 ???? public ?String?name;
          ?9 }

          10
          11 class ?DOG? implements ?Cloneable
          12 {
          13 ???? public ?DOG(String?name,? int ?age,?AAA?birthday)
          14 ???? {
          15 ???????? this .name? = ?name;
          16 ???????? this .age? = ?age;
          17 ???????? this .birthday? = ?birthday;
          18 ????}

          19
          20 ???? public ?String?getName()
          21 ???? {
          22 ???????? return ?name;
          23 ????}

          24
          25 ???? public ? int ?getAge()
          26 ???? {
          27 ???????? return ?age;
          28 ????}

          29
          30 ???? public ?AAA?getBirthday()
          31 ???? {
          32 ???????? return ?birthday;
          33 ????}

          34
          35 ???? public ?String?getBirth(AAA?a)
          36 ???? {
          37 ???????? return ?a.name;
          38 ????}

          39
          40 ???? public ?String?name;
          41
          42 ???? private ? int ?age;
          43
          44 ???? public ?AAA?birthday;
          45
          46 ???? public ?Object?clone()
          47 ???? {
          48 ???????? try
          49 ???????? {
          50 ???????????? super .clone();
          51 ???????????? return ? super .clone();
          52 ????????}
          ? catch ?(Exception?e)
          53 ???????? {
          54 ???????????? return ? null ;
          55 ????????}

          56 ????}

          57 }

          58
          59 public ? class ?TestClone
          60 {
          61 ???? public ? static ? void ?main(String[]?args)
          62 ???? {
          63 ????????AAA?Day? = ? new ?AAA( " test " );
          64 ????????DOG?dog1? = ? new ?DOG( " xiaogou " ,? 2 ,?Day);
          65 ????????DOG?dog2? = ?(DOG)?dog1.clone();
          66 ???????? // ??dog2.birthday?=?(AAA)?dog1.birthday.clone();?
          67 ????????dog1.birthday.name? = ? " 333 " ;
          68 ????????System.out.println(dog1.getBirth(dog1.birthday));
          69 ????????System.out.println(dog2.getBirth(dog2.birthday));
          70 ????}

          71 }

          72


          運行結果是:
          333
          333
          而真正要實現拷貝還的加點代碼,如下請對比上面和下面代碼的異同之處:

          ?1 class ?AAA? implements ?Cloneable
          ?2 {
          ?3 ???? public ?AAA(String?name)
          ?4 ???? {
          ?5 ???????? this .name? = ?name;
          ?6 ????}

          ?7
          ?8 ???? public ?Object?clone()
          ?9 ???? {
          10 ???????? try
          11 ???????? {
          12 ???????????? super .clone();
          13 ???????????? return ? super .clone();
          14 ????????}
          ? catch ?(Exception?e)
          15 ???????? {
          16 ???????????? return ? null ;
          17 ????????}

          18 ????}

          19
          20 ???? public ?String?name;
          21 }

          22
          23 class ?DOG? implements ?Cloneable
          24 {
          25 ???? public ?DOG(String?name,? int ?age,?AAA?birthday)
          26 ???? {
          27 ???????? this .name? = ?name;
          28 ???????? this .age? = ?age;
          29 ???????? this .birthday? = ?birthday;
          30 ????}

          31
          32 ???? public ?String?getName()
          33 ???? {
          34 ???????? return ?name;
          35 ????}

          36
          37 ???? public ? int ?getAge()
          38 ???? {
          39 ???????? return ?age;
          40 ????}

          41
          42 ???? public ?AAA?getBirthday()
          43 ???? {
          44 ???????? return ?birthday;
          45 ????}

          46
          47 ???? public ?String?getBirth(AAA?a)
          48 ???? {
          49 ???????? return ?a.name;
          50 ????}

          51
          52 ???? public ?String?name;
          53
          54 ???? private ? int ?age;
          55
          56 ???? public ?AAA?birthday;
          57
          58 ???? public ?Object?clone()
          59 ???? {
          60 ???????? try
          61 ???????? {
          62 ???????????? super .clone();
          63 ???????????? return ? super .clone();
          64 ????????}
          ? catch ?(Exception?e)
          65 ???????? {
          66 ???????????? return ? null ;
          67 ????????}

          68 ????}

          69 }

          70
          71 public ? class ?TestClone
          72 {
          73 ???? public ? static ? void ?main(String[]?args)
          74 ???? {
          75 ????????AAA?Day? = ? new ?AAA( " test " );
          76 ????????DOG?dog1? = ? new ?DOG( " xiaogou " ,? 2 ,?Day);
          77 ????????DOG?dog2? = ?(DOG)?dog1.clone();
          78 ????????dog2.birthday? = ?(AAA)?dog1.birthday.clone(); // 特別注意這里
          79 ????????dog1.birthday.name? = ? " 333 " ;
          80 ????????System.out.println(dog1.getBirth(dog1.birthday));
          81 ????????System.out.println(dog2.getBirth(dog2.birthday));
          82 ????}

          83 }

          84


          運行結果:
          333
          test
          這樣基本就達到了我們當初的母的。


          但是明顯的這種方法還是有許多不足,人們總是希望一個clone就是對象直接克隆。而上面還要對對象中的對象遞歸使用clone。下面提供一種更高級點的做法:

          ?

          ?1 import ?java.io. * ;
          ?2
          ?3 class ?AAA? implements ?Serializable
          ?4 {
          ?5 ???? public ?AAA(String?name)
          ?6 ???? {
          ?7 ???????? this .name? = ?name;
          ?8 ????}

          ?9
          10 ???? public ?String?name;
          11 }

          12
          13 class ?DOG? extends ?SerialCloneable
          14 {
          15 ???? public ?DOG(String?name,? int ?age,?AAA?birthday)
          16 ???? {
          17 ???????? this .name? = ?name;
          18 ???????? this .age? = ?age;
          19 ???????? this .birthday? = ?birthday;
          20 ????}

          21
          22 ???? public ?String?getName()
          23 ???? {
          24 ???????? return ?name;
          25 ????}

          26
          27 ???? public ? int ?getAge()
          28 ???? {
          29 ???????? return ?age;
          30 ????}

          31
          32 ???? public ?AAA?getBirthday()
          33 ???? {
          34 ???????? return ?birthday;
          35 ????}

          36
          37 ???? public ?String?getBirth(AAA?a)
          38 ???? {
          39 ???????? return ?a.name;
          40 ????}

          41
          42 ???? public ?String?name;
          43
          44 ???? private ? int ?age;
          45
          46 ???? public ?AAA?birthday;
          47
          48 ???? public ?Object?clone()
          49 ???? {
          50 ???????? try
          51 ???????? {
          52 ???????????? super .clone();
          53 ???????????? return ? super .clone();
          54 ????????}
          ? catch ?(Exception?e)
          55 ???????? {
          56 ???????????? return ? null ;
          57 ????????}

          58 ????}

          59 }

          60
          61 public ? class ?TestClone
          62 {
          63 ???? public ? static ? void ?main(String[]?args)
          64 ???? {
          65 ????????AAA?Day? = ? new ?AAA( " test " );
          66 ????????DOG?dog1? = ? new ?DOG( " xiaogou " ,? 2 ,?Day);
          67 ????????DOG?dog2? = ?(DOG)?dog1.clone();
          68 ???????? // dog2.birthday?=?(AAA)?dog1.birthday.clone();
          69 ????????dog1.birthday.name? = ? " 333 " ;
          70 ????????System.out.println(dog1.getBirth(dog1.birthday));
          71 ????????System.out.println(dog2.getBirth(dog2.birthday));
          72 ????}

          73 }

          74
          75 class ?SerialCloneable? implements ?Cloneable,?Serializable
          76 {
          77 ???? public ?Object?clone()
          78 ???? {
          79 ???????? try
          80 ???????? {
          81 ????????????ByteArrayOutputStream?bout? = ? new ?ByteArrayOutputStream();
          82 ????????????ObjectOutputStream?out? = ? new ?ObjectOutputStream(bout);
          83 ????????????out.writeObject( this );
          84 ????????????out.close();
          85 ????????????ByteArrayInputStream?bin? = ? new ?ByteArrayInputStream(bout
          86 ????????????????????.toByteArray());
          87 ????????????ObjectInputStream?in? = ? new ?ObjectInputStream(bin);
          88 ????????????Object?ret? = ?in.readObject();
          89 ????????????in.close();
          90 ???????????? return ?ret;
          91 ????????}
          ? catch ?(Exception?e)
          92 ???????? {
          93 ???????????? return ? null ;
          94 ????????}

          95 ????}

          96 }

          97


          輸出:
          333
          test

          上面的代碼用序列化與反序列化實現了對象拷貝。比較通用。但是得注意的是其中的類得implements Serializable。

          ?

          3)后記

          我們如果利用強大的反射機制+序列化與反序列化,能做出更加靈活的對象拷貝。有興趣的朋友可以自行去研究。
          我在javaeye上看到一篇短文:http://www.javaeye.com/post/367014 主要講的就是反射在對象拷貝中的應用。


          ?

          posted on 2008-04-28 11:52 -274°C 閱讀(10462) 評論(6)  編輯  收藏 所屬分類: JAVA


          FeedBack:
          # re: JAVA 對象拷貝
          2008-04-28 12:51 | Jacky-Q
          這代碼縮進真難受....  回復  更多評論
            
          # re: JAVA 對象拷貝
          2008-04-28 14:40 | 々上善若水々
          風中葉的吧。  回復  更多評論
            
          # re: JAVA 對象拷貝
          2008-04-29 10:47 | cc
          super .clone();
          return super .clone();
          這里為什么要寫兩次呢,直接寫
          return super .clone();
          不是更好嗎?  回復  更多評論
            
          # re: JAVA 對象拷貝
          2008-04-29 12:44 | java-he
          @ CC
          同意。  回復  更多評論
            
          # re: JAVA 對象拷貝[未登錄]
          2008-04-30 13:56 | java
          不錯~  回復  更多評論
            
          # re: JAVA 對象拷貝
          2012-07-02 11:25 | j2
          樓主連什么是遞歸都沒有搞清楚,錯別字,錯概念太多了  回復  更多評論
            

          常用鏈接

          留言簿(21)

          隨筆分類(265)

          隨筆檔案(242)

          相冊

          JAVA網站

          關注的Blog

          搜索

          •  

          積分與排名

          • 積分 - 914173
          • 排名 - 40

          最新評論

          主站蜘蛛池模板: 拜泉县| 思茅市| 石渠县| 侯马市| 广灵县| 阳高县| 防城港市| 永城市| 读书| 五莲县| 红桥区| 肇源县| 兴山县| 大荔县| 北川| 江华| 金溪县| 利辛县| 浮梁县| 辽阳市| 丰县| 瓦房店市| 南召县| 张家港市| 苍山县| 大安市| 甘德县| 双峰县| 佛冈县| 宁都县| 青海省| 屯昌县| 新绛县| 龙陵县| 高邑县| 芦溪县| 鄂温| 永吉县| 新安县| 阿巴嘎旗| 五莲县|