Wayne
          井底的蛙--一直仰望著天空
          posts - 16,comments - 6,trackbacks - 0

                Java語言的一個優點就是取消了指針的概念,但也導致了許多程序員在編程中常常忽略了對象與引用(此引用非C++中的引用)的區別,特別是先學c、c++后學java的程序員。并且由于Java不能通過簡單的賦值來解決對象復制的問題,在開發過程中,也常常要要應用clone()方法來復制對象。比如函數參數類型是自定義的類時,此時便是引用傳遞而不是值傳遞。以下是一個小例子:

          1. public class A {  
          2.     public String name;  
          3. }  

           

          1. public class testClone {  
          2.       
          3.     public void changeA(A a){  
          4.         a.name="b";  
          5.     }  
          6.     public void changInt(int i){  
          7.         i=i*2+100;  
          8.     }  
          9.       
          10.     /** 
          11.      * @param args 
          12.      */  
          13.     public static void main(String[] args) {  
          14.         // TODO Auto-generated method stub  
          15.         testClone test=new testClone();  
          16.         A a=new A();  
          17.         a.name="a";  
          18.         System.out.println("before change : a.name="+a.name);  
          19.         test.changeA(a);  
          20.         System.out.println("after  change : a.name="+a.name);  
          21.         int i=1;  
          22.         System.out.println("before change : i="+i);  
          23.         test.changInt(i);  
          24.         System.out.println("after  change : i="+i);  
          25.     }  
          26.   
          27. }  



          此時輸出的結果是:

          1. before change : a.name=a  
          2. after  change : a.name=b  
          3. before change : i=1  
          4. after  change : i=1  



                  從這個例子知道Java對對象和基本的數據類型的處理是不一樣的。在Java中用對象的作為入口參數的傳遞則缺省為"引用傳遞",也就是說僅僅傳遞了對象的一個"引用",這個"引用"的概念同C語言中的指針引用是一樣的。當函數體內部對輸入變量改變時,實質上就是在對這個對象的直接操作。 
          除了在函數傳值的時候是"引用傳遞",在任何用"="向對象變量賦值的時候都是"引用傳遞",如:

          1. A a1=new A();  
          2. A a2=new A();  
          3. a1.name="a1";  
          4. a2=a1;  
          5. a2.name="a2";  
          6. System.out.println("a1.name="+a1.name);  
          7. System.out.println("a2.name="+a2.name);  



                此時輸出的結果是:

          1. a1.name=a2  
          2. a2.name=a2  



                如果我們要用a2保存a1對象的數據,但又不希望a2對象數據被改變時不影響到a1。實現clone()方法是其一種最簡單,也是最高效的手段。 
          下面我們來實現A的clone方法

          1. public class A implements Cloneable {  
          2.     public String name;  
          3.   
          4.     public Object clone() {  
          5.         A o = null;  
          6.         try {  
          7.             o = (A) super.clone();  
          8.         } catch (CloneNotSupportedException e) {  
          9.             e.printStackTrace();  
          10.         }  
          11.         return o;  
          12.     }  
          13.   
          14. }  


                首先要實現Cloneable接口,然后在重載clone方法,最后在clone()方法中調用了super.clone(),這也意味著無論clone類的繼承結構是什么樣的,super.clone()直接或間接調用了java.lang.Object類的clone()方法。

          1. A a1=new A();  
          2. A a2=new A();  
          3. a1.name="a1";  
          4. a2=a1;  
          5. a2.name="a2";  
          6. System.out.println("a1.name="+a1.name);  
          7. System.out.println("a2.name="+a2.name);  



                此時輸出的結果是:

          1. a1.name=a1  
          2. a2.name=a2  



                當Class A成員變量類型是java的基本類型時(外加String類型),只要實現如上簡單的clone(稱影子clone)就可以。但是如果Class A成員變量是數組或復雜類型時,就必須實現深度clone。

          1. public class A implements Cloneable {  
          2.     public String name[];  
          3.       
          4.     public A(){  
          5.         name=new String[2];  
          6.     }  
          7.   
          8.     public Object clone() {  
          9.         A o = null;  
          10.         try {  
          11.             o = (A) super.clone();  
          12.         } catch (CloneNotSupportedException e) {  
          13.             e.printStackTrace();  
          14.         }  
          15.         return o;  
          16.     }  
          17. }  


                測試代碼

          1. A a1=new A();  
          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]);  


          輸出結果:

          1. a1.name=[Ljava.lang.String;@757aef  
          2. a1.name=b1  
          3. a2.name=[Ljava.lang.String;@757aef  
          4. a2.name=b1  


          看到了吧,a1.name,a2.name的hash值都是@757aef,也就是說影子clone對name數組只是clone他們的地址!解決該辦法是進行深度clone。

          1. public Object clone() {  
          2.         A o = null;  
          3.         try {  
          4.             o = (A) super.clone();  
          5.             o.name=(String[])name.clone();//其實也很簡單^_^  
          6.         } catch (CloneNotSupportedException e) {  
          7.             e.printStackTrace();  
          8.         }  
          9.         return o;  
          10.     }  


          此時輸出結果是:

          1. a1.name=[Ljava.lang.String;@757aef  
          2. a1.name=a1  
          3. a2.name=[Ljava.lang.String;@d9f9c3  
          4. a2.name=b1  


          需要注意的是Class A存在更為復雜的成員變量時,如Vector等存儲對象地址的容器時,就必須clone徹底。

          1. public class A implements Cloneable {  
          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.             o.name==(String[])name.clone();//深度clone  
          15.             o.claB=new Vector<B>();//將clone進行到底  
          16.             for(int i=0;i<claB.size();i++){  
          17.                 B temp=(B)claB.get(i).clone();//當然Class B也要實現相應clone方法  
          18.                 o.claB.add(temp);  
          19.             }  
          20.         } catch (CloneNotSupportedException e) {  
          21.             e.printStackTrace();  
          22.         }  
          23.                 return o;  
          24.     }  
          25. }  
          posted on 2010-08-28 17:21 waynewan 閱讀(328) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 项城市| 海阳市| 榆中县| 都昌县| 兴安县| 拜城县| 广昌县| 界首市| 台前县| 交城县| 金乡县| 陆丰市| 晋宁县| 鲁甸县| 通江县| 盐源县| 蕲春县| 上高县| 崇义县| 阿巴嘎旗| 浑源县| 宁陕县| 江津市| 浮梁县| 安泽县| 察雅县| 盖州市| 榕江县| 交口县| 清远市| 津南区| 永昌县| 通州市| 龙川县| 靖边县| 长春市| 林甸县| 大渡口区| 天峻县| 鸡泽县| 阿拉善左旗|