qileilove

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

          Java clone()方法來(lái)由及用法

          ava語(yǔ)言的一個(gè)優(yōu)點(diǎn)就是取消了指針的概念,但也導(dǎo)致了許多程序員在編程中常常忽略了對(duì)象與引用的區(qū)別,特別是先學(xué)c、c++后學(xué)java的程序員。并且由于Java不能通過(guò)簡(jiǎn)單的賦值來(lái)解決對(duì)象復(fù)制的問(wèn)題,在開(kāi)發(fā)過(guò)程中,也常常要要應(yīng)用clone()方法來(lái)復(fù)制對(duì)象。比如函數(shù)參數(shù)類(lèi)型是自定義的類(lèi)時(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對(duì)對(duì)象和基本的數(shù)據(jù)類(lèi)型的處理是不一樣的。在Java中用對(duì)象的作為入口參數(shù)的傳遞則缺省為"引用傳遞",也就是說(shuō)僅僅傳遞了對(duì)象的一個(gè)"引用",這個(gè)"引用"的概念同C語(yǔ)言中的指針引用是一樣的。當(dāng)函數(shù)體內(nèi)部對(duì)輸入變量改變時(shí),實(shí)質(zhì)上就是在對(duì)這個(gè)對(duì)象的直接操作。
            除了在函數(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對(duì)象的數(shù)據(jù),但又不希望a2對(duì)象數(shù)據(jù)被改變時(shí)不影響到a1。實(shí)現(xiàn)clone()方法是其一種最簡(jiǎn)單,也是最高效的手段。
            下面我們來(lái)實(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(),這也意味著無(wú)論clone類(lèi)的繼承結(jié)構(gòu)是什么樣的,super.clone()直接或間接調(diào)用了java.lang.Object類(lèi)的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成員變量類(lèi)型是java的基本類(lèi)型時(shí)(外加String類(lèi)型),只要實(shí)現(xiàn)如上簡(jiǎn)單的clone(稱影子clone)就可以。但是如果Class A成員變量是數(shù)組或復(fù)雜類(lèi)型時(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;
          }
          }
            測(cè)試代碼
          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,也就是說(shuō)影子clone對(duì)name數(shù)組只是clone他們的地址!解決該辦法是進(jìn)行深度clone。
          public Object clone() {
          A o = null;
          try {
          o = (A) super.clone();
          o.name=(String[])name.clone();//其實(shí)也很簡(jiǎn)單^_^
          } 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ǔ)對(duì)象地址的容器時(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) 評(píng)論(0)  編輯  收藏


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


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

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(55)

          隨筆分類(lèi)

          隨筆檔案

          文章分類(lèi)

          文章檔案

          搜索

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 舟曲县| 常宁市| 湘潭县| 肥乡县| 绿春县| 桐梓县| 古田县| 来宾市| 汾阳市| 鲁甸县| 大姚县| 上虞市| 武汉市| 蓬溪县| 湘潭县| 当阳市| 凤台县| 南汇区| 南皮县| 荥经县| 长顺县| 岑溪市| 祁东县| 忻州市| 思南县| 苏尼特右旗| 望奎县| 隆子县| 呼伦贝尔市| 呼图壁县| 钦州市| 贡觉县| 宁武县| 调兵山市| 师宗县| 屯门区| 西城区| 开鲁县| 梅河口市| 湘潭县| 济宁市|