qileilove

          blog已經(jīng)轉(zhuǎn)移至github,大家請?jiān)L問 http://qaseven.github.io/

          Java clone()方法來由及用法

          ava語言的一個(gè)優(yōu)點(diǎn)就是取消了指針的概念,但也導(dǎo)致了許多程序員在編程中常常忽略了對象與引用的區(qū)別,特別是先學(xué)c、c++后學(xué)java的程序員。并且由于Java不能通過簡單的賦值來解決對象復(fù)制的問題,在開發(fā)過程中,也常常要要應(yīng)用clone()方法來復(fù)制對象。比如函數(shù)參數(shù)類型是自定義的類時(shí),此時(shí)便是引用傳遞而不是值傳遞。以下是一個(gè)小例子:
          public class A {
          public String name;
          }
          public class testClone {
          public void changeA(A a){
          a.name="b";
          }
          public void changInt(int i){
          i=i*2+100;
          }
          /**
          * @param args
          */
          public static void main(String[] args) {
          // TODO Auto-generated method stub
          testClone test=new testClone();
          A a=new A();
          a.name="a";
          System.out.println("before change : a.name="+a.name);
          test.changeA(a);
          System.out.println("after  change : a.name="+a.name);
          int i=1;
          System.out.println("before change : i="+i);
          test.changInt(i);
          System.out.println("after  change : i="+i);
          }
          }
            此時(shí)輸出的結(jié)果是:
          before change : a.name=a
          after  change : a.name=b
          before change : i=1
          after  change : i=1

          從這個(gè)例子知道Java對對象和基本的數(shù)據(jù)類型的處理是不一樣的。在Java中用對象的作為入口參數(shù)的傳遞則缺省為"引用傳遞",也就是說僅僅傳遞了對象的一個(gè)"引用",這個(gè)"引用"的概念同C語言中的指針引用是一樣的。當(dāng)函數(shù)體內(nèi)部對輸入變量改變時(shí),實(shí)質(zhì)上就是在對這個(gè)對象的直接操作。
            除了在函數(shù)傳值的時(shí)候是"引用傳遞",在任何用"="向?qū)ο笞兞抠x值的時(shí)候都是"引用傳遞",如:
          A a1=new A();
          A a2=new A();
          a1.name="a1";
          a2=a1;
          a2.name="a2";
          System.out.println("a1.name="+a1.name);
          System.out.println("a2.name="+a2.name);
            此時(shí)輸出的結(jié)果是:
            a1.name=a2
            a2.name=a2
            如果我們要用a2保存a1對象的數(shù)據(jù),但又不希望a2對象數(shù)據(jù)被改變時(shí)不影響到a1。實(shí)現(xiàn)clone()方法是其一種最簡單,也是最高效的手段。
            下面我們來實(shí)現(xiàn)A的clone方法
          public class A implements Cloneable {
          public String name;
          public Object clone() {
          A o = null;
          try {
          o = (A) super.clone();
          } catch (CloneNotSupportedException e) {
          e.printStackTrace();
          }
          return o;
          }
          }
            首先要實(shí)現(xiàn)Cloneable接口,然后在重載clone方法,最后在clone()方法中調(diào)用了super.clone(),這也意味著無論clone類的繼承結(jié)構(gòu)是什么樣的,super.clone()直接或間接調(diào)用了java.lang.Object類的clone()方法。
          A a1=new A();
          A a2=new A();
          a1.name="a1";
          a2=a1;
          a2.name="a2";
          System.out.println("a1.name="+a1.name);
          System.out.println("a2.name="+a2.name);
            此時(shí)輸出的結(jié)果是:
            a1.name=a1
            a2.name=a2
            當(dāng)Class A成員變量類型是java的基本類型時(shí)(外加String類型),只要實(shí)現(xiàn)如上簡單的clone(稱影子clone)就可以。但是如果Class A成員變量是數(shù)組或復(fù)雜類型時(shí),就必須實(shí)現(xiàn)深度clone。
          public class A implements Cloneable {
          public String name[];
          public A(){
          name=new String[2];
          }
          public Object clone() {
          A o = null;
          try {
          o = (A) super.clone();
          } catch (CloneNotSupportedException e) {
          e.printStackTrace();
          }
          return o;
          }
          }
            測試代碼
          A a1=new A();
          A a2=new A();
          a1.name[0]="a";
          a1.name[1]="1";
          a2=(A)a1.clone();
          a2.name[0]="b";
          a2.name[1]="1";
          System.out.println("a1.name="+a1.name);
          System.out.println("a1.name="+a1.name[0]+a1.name[1]);
          System.out.println("a2.name="+a2.name);
          System.out.println("a2.name="+a2.name[0]+a2.name[1]);
            輸出結(jié)果:
            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數(shù)組只是clone他們的地址!解決該辦法是進(jìn)行深度clone。
          public Object clone() {
          A o = null;
          try {
          o = (A) super.clone();
          o.name=(String[])name.clone();//其實(shí)也很簡單^_^
          } catch (CloneNotSupportedException e) {
          e.printStackTrace();
          }
          return o;
          }
            此時(shí)輸出結(jié)果是:
            a1.name=[Ljava.lang.String;@757aef
            a1.name=a1
            a2.name=[Ljava.lang.String;@d9f9c3
            a2.name=b1
            需要注意的是Class A存在更為復(fù)雜的成員變量時(shí),如Vector等存儲(chǔ)對象地址的容器時(shí),就必須clone徹底。
          public class A implements Cloneable {
          public String name[];
          public Vector<B> claB;
          public A(){
          name=new String[2];
          claB=new Vector<B>();
          }
          public Object clone() {
          A o = null;
          try {
          o = (A) super.clone();
          o.name==(String[])name.clone();//深度clone
          o.claB=new Vector<B>();//將clone進(jìn)行到底
          for(int i=0;i<claB.size();i++){
          B temp=(B)claB.get(i).clone();//當(dāng)然Class B也要實(shí)現(xiàn)相應(yīng)clone方法
          o.claB.add(temp);
          }
          } catch (CloneNotSupportedException e) {
          e.printStackTrace();
          }
          return o;
          }
          }

          posted on 2013-12-09 10:37 順其自然EVO 閱讀(253) 評論(0)  編輯  收藏


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


          網(wǎng)站導(dǎo)航:
           
          <2013年12月>
          24252627282930
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 靖远县| 宜昌市| 嘉义县| 四平市| 澄江县| 新泰市| 轮台县| 翁牛特旗| 肇东市| 宿松县| 中阳县| 海阳市| 临朐县| 杭锦后旗| 温泉县| 兴和县| 彰化县| 巴东县| 青冈县| 眉山市| 江西省| 越西县| 兴隆县| 南充市| 无极县| 瑞昌市| 西充县| 出国| 台州市| 东乡族自治县| 麻城市| 永济市| 汶上县| 美姑县| 类乌齐县| 甘孜| 富川| 九寨沟县| 水富县| 佛冈县| 洛阳市|