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

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

          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. }  



          此時輸出的結(jié)果是:

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



                  從這個例子知道Java對對象和基本的數(shù)據(jù)類型的處理是不一樣的。在Java中用對象的作為入口參數(shù)的傳遞則缺省為"引用傳遞",也就是說僅僅傳遞了對象的一個"引用",這個"引用"的概念同C語言中的指針引用是一樣的。當(dāng)函數(shù)體內(nèi)部對輸入變量改變時,實質(zhì)上就是在對這個對象的直接操作。 
          除了在函數(shù)傳值的時候是"引用傳遞",在任何用"="向?qū)ο笞兞抠x值的時候都是"引用傳遞",如:

          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);  



                此時輸出的結(jié)果是:

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



                如果我們要用a2保存a1對象的數(shù)據(jù),但又不希望a2對象數(shù)據(jù)被改變時不影響到a1。實現(xiàn)clone()方法是其一種最簡單,也是最高效的手段。 
          下面我們來實現(xiàn)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. }  


                首先要實現(xiàn)Cloneable接口,然后在重載clone方法,最后在clone()方法中調(diào)用了super.clone(),這也意味著無論clone類的繼承結(jié)構(gòu)是什么樣的,super.clone()直接或間接調(diào)用了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);  



                此時輸出的結(jié)果是:

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



                當(dāng)Class A成員變量類型是java的基本類型時(外加String類型),只要實現(xiàn)如上簡單的clone(稱影子clone)就可以。但是如果Class A成員變量是數(shù)組或復(fù)雜類型時,就必須實現(xiàn)深度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]);  


          輸出結(jié)果:

          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數(shù)組只是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.     }  


          此時輸出結(jié)果是:

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


          需要注意的是Class A存在更為復(fù)雜的成員變量時,如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();//當(dāng)然Class B也要實現(xiàn)相應(yīng)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 閱讀(329) 評論(0)  編輯  收藏

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


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 安龙县| 平泉县| 阆中市| 峨眉山市| 珲春市| 务川| 永和县| 漯河市| 威宁| 通山县| 商洛市| 农安县| 恩平市| 通海县| 巩留县| 通化县| 哈尔滨市| 南城县| 灵璧县| 昌平区| 沙坪坝区| 湘潭县| 洪泽县| 祥云县| 尚志市| 高阳县| 永州市| 徐闻县| 芜湖市| 武乡县| 湛江市| 前郭尔| 高清| 法库县| 九寨沟县| 阳泉市| 敦化市| 交口县| 满洲里市| 遂川县| 固始县|