JAVA 對象拷貝

JAVA 對象拷貝java

爲何須要有對象拷貝?post

對象拷貝相對的天然是引用拷貝。java初學者常常會問,我這個方法要改變一個對象的屬性,能夠把參數傳進去了,爲何沒有改變了?this

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

而有時候咱們要獲取到一個當前狀態的對象複製品,他們是兩個獨立對象。再也不是引用或者引用拷貝(實質都是指向對象自己)。就是說a是b的拷貝,b發生變化的時候,不要影響a。.net


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

1)淺拷貝blog

淺拷貝是指對象中基本數據類型獲得拷貝,而引用數據類型並未拷貝。
提到拷貝天然和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
2get

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 主要講的就是反射在對象拷貝中的應用。

相關文章
相關標籤/搜索