Java語言的一個優點就是取消了指針的概念,但也導致了許多程序員在編程中常常忽略了對象與引用的區別,特別是先學c、c++后學java的程序員。并且由于Java不能通過簡單的賦值來解決對象復制的問題,在開發過程中,也常常要要應用clone()方法來復制對象。比如函數參數類型是自定義的類時,此時便是引用傳遞而不是值傳遞。以下是一個小例子:
2 ??? public String name;??
3 }
4 public class testClone {??????????
5 ???? public void changeA(A a){??
6 ????????? a.name="b" ;??
7 ???? }??
8 ????? public void changInt( int i){??
9 ????????? i=i*2+100 ;??
10 ???? }??
11 ????????
12 ????? /** ?
13 ????? * @param args?
14 ?????? */ ?
15 ????? public static void main(String[] args) {??
16 ????????? // TODO Auto-generated method stub??
17 ????????? testClone test= new testClone();??
18 ????????? A a= new A();??
19 ????????? a.name="a" ;??
20 ????????? System.out.println("before change : a.name="+ a.name);??
21 ???????? test.changeA(a);??
22 ????????? System.out.println("after? change : a.name="+ a.name);??
23 ????????? int i=1 ;??
24 ????????? System.out.println("before change : i="+ i);??
25 ???????? test.changInt(i);??
26 ????????? System.out.println("after? change : i="+ i);??
27 ??? }??
28 ???
29 ? }

此時輸出的結果是:
before change : a.name=a
after? change : a.name=b
before change : i=1
after? change : i=1
從這個例子知道Java對對象和基本的數據類型的處理是不一樣的。在Java中用對象的作為入口參數的傳遞則缺省為"引用傳遞",也就是說僅僅傳遞了對象的一個"引用",這個"引用"的概念同C語言中的指針引用是一樣的。當函數體內部對輸入變量改變時,實質上就是在對這個對象的直接操作。
除了在函數傳值的時候是"引用傳遞",在任何用"="向對象變量賦值的時候都是"引用傳遞",如:
?
此時輸出的結果是:
a1.name=a2
a2.name=a2
如果我們要用a2保存a1對象的數據,但又不希望a2對象數據被改變時不影響到a1。實現clone()方法是其一種最簡單,也是最高效的手段。
下面我們來實現A的clone方法
3 ???? public String name;
4
5 ???? public Object clone()
6 ??? {
7 ???????? A o = null ;
8 ???????? try
9 ??????? {
10 ???????????? o = (A) super .clone();
11 ???????? } catch (CloneNotSupportedException e)
12 ??????? {
13 e.printStackTrace(); 14 ??????? }
15 ???????? return o;
16 ??? }
17 }

首先要實現Cloneable接口,然后在重載clone方法,最后在clone()方法中調用了super.clone(),這也意味著無論clone類的繼承結構是什么樣的,super.clone()直接或間接調用了java.lang.Object類的clone()方法。
此時輸出的結果是:
a1.name=a1
a2.name=a2
當Class A成員變量類型是java的基本類型時(外加String類型),只要實現如上簡單的clone(稱影子clone)就可以。但是如果Class A成員變量是數組或復雜類型時,就必須實現深度clone。
3 ???? public String name[];
4
5 ???? public A()
6 ??? {
7 ???????? name = new String[2 ];
8 ??? }
9
10 ???? public Object clone()
11 ??? {
12 ???????? A o = null ;
13 ???????? try
14 ??????? {
15 ???????????? o = (A) super .clone();
16 ???????? } catch (CloneNotSupportedException e)
17 ??????? {
18 e.printStackTrace(); 19 ??????? }
20 ???????? return o;
21 ??? }
22 }

測試代碼
2 A a2= new A();
3 a1.name[0]="a" ;
4 a1.name[1]="1" ;
5 a2= (A)a1.clone();
6 a2.name[0]="b" ;
7 a2.name[1]="1" ;
8 System.out.println("a1.name="+ a1.name);
9 System.out.println("a1.name="+a1.name[0]+a1.name[1 ]);
10 System.out.println("a2.name="+ a2.name);
11 System.out.println("a2.name="+a2.name[0]+a2.name[1]);

輸出結果:
a1.name=[Ljava.lang.String;@757aef
a1.name=b1
a2.name=[Ljava.lang.String;@757aef
a2.name=b1
看到了吧,a1.name,a2.name的hash值都是@757aef,也就是說影子clone對name數組只是clone他們的地址!解決該辦法是進行深度clone。
2 ??? {
3 ???????? A o = null ;
4 ???????? try
5 ??????? {
6 ???????????? o = (A) super .clone();
7 ???????? } catch (CloneNotSupportedException e)
8 ??????? {
9 e.printStackTrace(); 10 ??????? }
11 ???????? o.name = new String[2]; // 其實也很簡單^_^
12 ???????? return o;
13 ???? }

此時輸出結果是:
a1.name=[Ljava.lang.String;@757aef
a1.name=a1
a2.name=[Ljava.lang.String;@d9f9c3
a2.name=b1
?
需要注意的是Class A存在更為復雜的成員變量時,如Vector等存儲對象地址的容器時,就必須clone徹底。
2 ????? public String name[];??
3 ????? public Vector<B> claB;??
4 ????????
5 ????? public A(){??
6 ????????? name= new String[2 ];??
7 ????????? claB= new Vector<B> ();??
8 ???? }??
9 ???
10 ????? public Object clone() {??
11 ????????? A o = null ;??
12 ????????? try {??
13 o = (A) super .clone();??
14 ????????? } catch (CloneNotSupportedException e) {??
15 ???????????? e.printStackTrace();??
16 ???????? }??
17 ????????? o.name= new String[2]; // 深度clone??
18 ????????? o.claB= new Vector<B>(); // 將clone進行到底??
19 ????????? for ( int i=0;i<claB.size();i++ ){??
20 ????????????? B temp=(B)claB.get(i).clone(); // 當然Class B也要實現相應clone方法
21 ???????????? o.claB.add(temp);??
22 ???????? }??
23 ????????? return o;??
24 ???? }??
25 ? }
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
