青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

woaidongmao

文章均收錄自他人博客,但不喜標題前加-[轉貼],因其丑陋,見諒!~
隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
數據加載中……

關于java對象復制

關于java對象復制
我們在編碼過程經常會碰到將一個對象傳遞給另一個對象,java中對于基本型變量
采用的是值傳遞,而對于對象比如bean傳遞時采用的是應用傳遞也就是地址傳遞,
而很多時候對于對象傳遞我們也希望能夠象值傳遞一樣,使得傳遞之前和之后有
不同的內存地址,在這種情況下我們一般采用以下兩種情況。

1
對象克隆
什么是"clone"


在實際編程過程中,我們常常要遇到這種情況:有一個對象A,在某一時刻A中已經包含了一些有效值,此時可能會需要一個和A完全相同新對象B,并且此后對B任何改動都不會影響到A中的值,也就是說,AB是兩個獨立的對象,但B的初始值是由A對象確定的。在Java語言中,用簡單的賦值語句是不能滿足這種需求的。要滿足這種需求雖然有很多途徑,但實現clone()方法是其中最簡單,也是最高效的手段。

Java
的所有類都默認繼承java.lang.Object類,在java.lang.Object類中有一個方法clone()JDK API的說明文檔解釋這個方法將返回Object對象的一個拷貝。要說明的有兩點:一是拷貝對象返回的是一個新對象,而不是一個引用。二是拷貝對象與用new操作符返回的新對象的區別就是這個拷貝已經包含了一些原來對象的信息,而不是對象的初始信息。

怎樣應用clone()方法?


一個很典型的調用clone()代碼如下:

class CloneClass implements Cloneable{
    public int aInt;
    public Object clone(){
        CloneClass o = null;
        try{
            o = (CloneClass)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return o;
    }





有三個值得注意的地方,一是希望能實現clone功能的CloneClass類實現了Cloneable接口,這個接口屬于java.lang包,java.lang包已經被缺省的導入類中,所以不需要寫成java.lang.Cloneable。另一個值得請注意的是重載了clone()方法。最后在clone()方法中調用了super.clone(),這也意味著無論clone類的繼承結構是什么樣的,super.clone()直接或間接調用了java.lang.Object類的clone()方法。下面再詳細的解釋一下這幾點。

應該說第三點是最重要的,仔細觀察一下Object類的clone()一個native方法,native方法的效率一般來說都是遠高于java中的非native方法。這也解釋了為什么要用Objectclone()方法而不是先new一個類,然后把原始對象中的信息賦到新對象中,雖然這也實現了clone功能。對于第二點,也要觀察Object類中的clone()還是一個protected屬性的方法。這也意味著如果要應用clone()方法,必須繼承Object類,在Java中所有的類是缺省繼承Object類的,也就不用關心這點了。然后重載clone()方法。還有一點要考慮的是為了讓其它類能調用這個clone類的clone()方法,重載之后要把clone()方法的屬性設置為public

那么clone類為什么還要實現Cloneable接口呢?稍微注意一下,Cloneable接口是不包含任何方法的!其實這個接口僅僅是一個標志,而且這個標志也僅僅是針對Object類中clone()方法的,如果clone類沒有實現Cloneable接口,并調用了Objectclone()方法(也就是調用了super.Clone()方法),那么Objectclone()方法就會拋出CloneNotSupportedException異常。

什么是影子clone


下面的例子包含三個類UnCloneACloneBCloneMainCloneB類包含了一個UnCloneA的實例和一個int類型變量,并且重載clone()方法。CloneMain類初始化UnCloneA類的一個實例b1,然后調用clone()方法生成了一個b1的拷貝b2。最后考察一下b1b2的輸出:

package clone;
class UnCloneA {
    private int i;
    public UnCloneA(int ii) { i = ii; }
    public void doubleValue() { i *= 2; }
    public String toString() {
        return Integer.toString(i);
    }
}
class CloneB implements Cloneable{
    public int aInt;
    public UnCloneA unCA = new UnCloneA(111);
    public Object clone(){
        CloneB o = null;
        try{
            o = (CloneB)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return o;
    }
}
public class CloneMain {
    public static void main(String[] a){
        CloneB b1 = new CloneB();
        b1.aInt = 11;
        System.out.println("before clone,b1.aInt = "+ b1.aInt);
        System.out.println("before clone,b1.unCA = "+ b1.unCA);
               
        CloneB b2 = (CloneB)b1.clone();
        b2.aInt = 22;
        b2.unCA.doubleValue();
        System.out.println("=================================");
        System.out.println("after clone,b1.aInt = "+ b1.aInt);
        System.out.println("after clone,b1.unCA = "+ b1.unCA);
        System.out.println("=================================");
        System.out.println("after clone,b2.aInt = "+ b2.aInt);
        System.out.println("after clone,b2.unCA = "+ b2.unCA);
    }
}


/** RUN RESULT:
before clone,b1.aInt = 11
before clone,b1.unCA = 111
=================================
after clone,b1.aInt = 11
after clone,b1.unCA = 222
=================================
after clone,b2.aInt = 22
after clone,b2.unCA = 222
*/





輸出的結果說明int類型的變量aIntUnCloneA的實例對象unCAclone結果不一致,int類型是真正的被clone了,因為改變了b2中的aInt變量,對b1aInt沒有產生影響,也就是說,b2.aIntb1.aInt已經占據了不同的內存空間,b2.aIntb1.aInt的一個真正拷貝。相反,對b2.unCA的改變同時改變了b1.unCA,很明顯,b2.unCAb1.unCA是僅僅指向同一個對象的不同引用!從中可以看出,調用Object類中clone()方法產生的效果是:先在內存中開辟一塊和原始對象一樣的空間,然后原樣拷貝原始對象中的內容。對基本數據類型,這樣的操作是沒有問題的,但對非基本類型變量,我們知道它們保存的僅僅是對象的引用,這也導致clone后的非基本類型變量和原始對象中相應的變量指向的是同一個對象。

大多時候,這種clone的結果往往不是我們所希望的結果,這種clone也被稱為"影子clone"。要想讓b2.unCA指向與b2.unCA不同的對象,而且b2.unCA中還要包含b1.unCA中的信息作為初始信息,就要實現深度clone

怎么進行深度clone


把上面的例子改成深度clone很簡單,需要兩個改變:一是讓UnCloneA類也實現和CloneB類一樣的clone功能(實現Cloneable接口,重載clone()方法)。二是在CloneBclone()方法中加入一句o.unCA = (UnCloneA)unCA.clone();

程序如下:

package clone.ext;
class UnCloneA implements Cloneable{
    private int i;
    public UnCloneA(int ii) { i = ii; }
    public void doubleValue() { i *= 2; }
    public String toString() {
        return Integer.toString(i);
    }
    public Object clone(){
        UnCloneA o = null;
        try{
            o = (UnCloneA)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        return o;
    }
}
class CloneB implements Cloneable{
    public int aInt;
    public UnCloneA unCA = new UnCloneA(111);
    public Object clone(){
        CloneB o = null;
        try{
            o = (CloneB)super.clone();
        }catch(CloneNotSupportedException e){
            e.printStackTrace();
        }
        o.unCA = (UnCloneA)unCA.clone();
        return o;
    }
}
public class CloneMain {
    public static void main(String[] a){
        CloneB b1 = new CloneB();
        b1.aInt = 11;
        System.out.println("before clone,b1.aInt = "+ b1.aInt);
        System.out.println("before clone,b1.unCA = "+ b1.unCA);
               
        CloneB b2 = (CloneB)b1.clone();
        b2.aInt = 22;
        b2.unCA.doubleValue();
        System.out.println("=================================");
        System.out.println("after clone,b1.aInt = "+ b1.aInt);
        System.out.println("after clone,b1.unCA = "+ b1.unCA);
        System.out.println("=================================");
        System.out.println("after clone,b2.aInt = "+ b2.aInt);
        System.out.println("after clone,b2.unCA = "+ b2.unCA);
    }
}

/** RUN RESULT:
before clone,b1.aInt = 11
before clone,b1.unCA = 111
=================================
after clone,b1.aInt = 11
after clone,b1.unCA = 111
=================================
after clone,b2.aInt = 22
after clone,b2.unCA = 222
*/





可以看出,現在b2.unCA的改變對b1.unCA沒有產生影響。此時b1.unCAb2.unCA指向了兩個不同的UnCloneA實例,而且在CloneB b2 = (CloneB)b1.clone();調用的那一刻b1b2擁有相同的值,在這里,b1.i = b2.i = 11

要知道不是所有的類都能實現深度clone的。例如,如果把上面的CloneB類中的UnCloneA類型變量改成StringBuffer類型,看一下JDK API中關于StringBuffer的說明,StringBuffer沒有重載clone()方法,更為嚴重的是StringBuffer還是一個final類,這也是說我們也不能用繼承的辦法間接實現StringBufferclone。如果一個類中包含有StringBuffer類型對象或和StringBuffer相似類的對象,我們有兩種選擇:要么只能實現影子clone,要么就在類的clone()方法中加一句(假設是SringBuffer對象,而且變量名仍是unCA): o.unCA = new StringBuffer(unCA.toString()); //原來的是:o.unCA = (UnCloneA)unCA.clone();

還要知道的是除了基本數據類型能自動實現深度clone以外,String對象是一個例外,它clone后的表現好象也實現了深度clone,雖然這只是一個假象,但卻大大方便了我們的編程。

通過以上我們可以看出在某些情況下,我們可以利用clone方法來實現對象只見的復制,但對于比較復雜的對象(比如對象中包含其他對象,其他對象又包含別的對象.....)這樣我們必須進行層層深度clone,每個對象需要實現cloneable接口,比較麻煩,那就繼續學習下一個序列化方法。

2
對象序列化

所謂對象序列化就是將對象的狀態轉換成字節流,以后可以通過這些值再生成相同狀態的對象。這個過程也可以通過網絡實現,可以先在Windows機器上創建一個對象,對其序列化,然后通過網絡發給一臺Unix機器,然后在那里準確無誤地重新裝配。是不是很神奇。

也許你會說,只了解一點點,但從來沒有接觸過,其實未必如此。RMISocketJMSEJB你總該用過一種吧,彼此為什么能夠傳遞Java對象,當然都是對象序列化機制的功勞。

第一次使用Java的對象序列化是做某項目,當時要求把幾棵非常復雜的樹(JTree)及相應的數據保存下來(就是我們常用的保存功能),以便下次運行程序時可以繼續上次的操作。

那時XML技術在網上非常的熱,而且功能也強大,再加上樹的結構本來就和XML存儲數據的格式很像。作為一項對新技術比較有興趣的我當然很想嘗試一下。不過經過仔細分析,發現如果采用XML保存數據,后果真是難以想象:哪棵樹的哪個節點被展開、展開到第幾級、節點當前的屬性是什么。真是不知該用ABC還是用123來表示。

還好,發現了Java的對象序列化機制,問題迎刃而解,只需簡單的將每棵樹的根節點序列化保存到硬盤上,下次再通過反序列化后的根節點就可以輕松的構造出和原來一模一樣的樹來。

其實保存數據,尤其是復雜數據的保存正是對象序列化的典型應用。最近另一個項目就遇到了需要對非常復雜的數據進行存取,通過使用對象的序列化,問題同樣化難為簡。

對象的序列化還有另一個容易被大家忽略的功能就是對象復制(Clone),Java中通過Clone機制可以復制大部分的對象,但是眾所周知,Clone有深層Clone和淺層Clone,如果你的對象非常非常復雜,假設有個100層的Collection(夸張了點),如果你想實現深層Clone,真是不敢想象,如果使用序列化,不會超過10行代碼就可以解決。

還有就是Swing組件,如果你有兩個很象很象(或是一模一樣)的比較難以構造的Swing組件,你該怎么辦,也許你想到了Clone,但是偏偏JavaSwing組件沒有提供Clone方法。別急,使用序列化,6行代碼搞定:

ByteArrayOutputStream
byteOut = new ByteArrayOutputStream();
ObjectOutputStream out
= new ObjectOutputStream(byteOut);
out.writeObject(combo);

ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in
=new ObjectInputStream(byteIn);
JComboBox comb2 = (JComboBox)in.readObject();


雖然Java的序列化非常簡單、強大,但是要用好,還有很多地方需要注意。比如曾經序列化了一個對象,可由于某種原因,該類做了一點點改動,然后重新被編譯,那么這時反序列化剛才的對象,將會出現異常。

你可以通過添加serialVersionUID屬性來解決這個問題。如果你的類是個單態(Singleton)類,是否允許用戶通過序列化機制復制該類,如果不允許你需要謹慎對待該類的實現。


    /**
     * Clone Object
     * @param obj
     * @return
     * @throws Exception
     */
    private Object cloneObject(Object obj) throws Exception{
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(obj);
       
        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in =new ObjectInputStream(byteIn);
       
        return in.readObject();
    }

參考資料:

1.http://www-128.ibm.com/developerworks/cn/java/l-jpointer/index.html

2.http://www.softexam.cn/eschool/details.asp?id=10930

posted on 2009-08-24 23:32 肥仔 閱讀(1748) 評論(1)  編輯 收藏 引用 所屬分類: Web-后臺

評論

# re: 關于java對象復制  回復  更多評論   

謝謝分享
2011-05-11 12:42 | 游客
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            性欧美xxxx视频在线观看| 91久久精品国产91性色| 欧美视频在线免费| 欧美国产日本韩| 欧美高清视频免费观看| 欧美gay视频| 蜜桃久久精品一区二区| 久久乐国产精品| 麻豆精品精品国产自在97香蕉| 久久亚洲私人国产精品va| 久久综合伊人77777| 欧美激情黄色片| 国产精品入口夜色视频大尺度| 国产欧美一区二区在线观看| 国产欧美 在线欧美| 国产午夜亚洲精品理论片色戒| 国产亚洲一区二区三区在线播放| 狠狠综合久久| 亚洲视频国产视频| 久久av老司机精品网站导航| 欧美aⅴ一区二区三区视频| 亚洲欧洲偷拍精品| 亚洲一区二区三区影院| 久久精品在线播放| 欧美日韩国产成人高清视频| 国产精品日日摸夜夜添夜夜av| 国产亚洲精品一区二区| 日韩亚洲欧美精品| 午夜亚洲激情| 欧美激情a∨在线视频播放| 一本色道久久综合狠狠躁的推荐| 香蕉久久夜色精品国产使用方法 | 久久精品综合网| 狂野欧美一区| 国产精品色一区二区三区| 今天的高清视频免费播放成人| 亚洲久色影视| 久久精品日韩一区二区三区| 欧美激情中文字幕乱码免费| 亚洲一区二区网站| 欧美精品性视频| 在线播放视频一区| 午夜日韩激情| 日韩亚洲视频在线| 免费久久99精品国产| 国产一区二区av| 亚洲视频在线视频| 亚洲高清自拍| 久久久久.com| 国产乱码精品一区二区三区忘忧草| 亚洲第一精品夜夜躁人人爽 | 欧美另类专区| 亚洲第一精品久久忘忧草社区| 欧美一区二区三区精品| 亚洲欧洲一区二区在线播放| 老巨人导航500精品| 国内外成人在线视频| 羞羞视频在线观看欧美| 99re8这里有精品热视频免费| 麻豆成人在线播放| 在线观看日韩精品| 欧美电影在线观看| 久久久久一本一区二区青青蜜月| 欧美精品v日韩精品v韩国精品v| 国产一区二区精品在线观看| 亚洲视频香蕉人妖| 亚洲激情在线| 欧美电影免费| 亚洲精品一区二区三区在线观看| 久久亚洲一区二区三区四区| 欧美一进一出视频| 国产在线精品成人一区二区三区| 午夜精品理论片| 亚洲欧美日韩一区二区在线| 国产精品一国产精品k频道56| 欧美性一区二区| 久久在线91| 亚洲国产你懂的| 亚洲黄色成人久久久| 亚洲一级在线观看| 一区二区三区精品视频在线观看| 欧美日韩国产欧美日美国产精品| 亚洲精品免费在线观看| 亚洲精品日韩在线观看| 欧美日精品一区视频| 亚洲欧美国产日韩中文字幕| 亚洲免费在线看| 影音先锋久久| 亚洲精品乱码久久久久久蜜桃麻豆| 欧美激情一区二区三区不卡| 亚洲一线二线三线久久久| 亚洲欧美日产图| 韩国精品一区二区三区| 亚洲国产精品国自产拍av秋霞| 欧美日韩日日骚| 久久久视频精品| 欧美日韩国产精品一卡| 久久黄金**| 欧美精品在线视频| 欧美主播一区二区三区| 欧美aⅴ99久久黑人专区| 亚洲视频免费在线| 久久精品水蜜桃av综合天堂| 一二三区精品福利视频| 欧美一区二区三区在| 亚洲人成网站精品片在线观看| 一本色道**综合亚洲精品蜜桃冫 | 欧美在线亚洲综合一区| 亚洲精品视频一区| 欧美一级视频免费在线观看| 亚洲美女诱惑| 久久国产天堂福利天堂| 亚洲综合首页| 蜜臀久久99精品久久久久久9| 香蕉久久一区二区不卡无毒影院| 欧美国产日韩一区二区在线观看 | 久久国产成人| 99综合在线| 久久免费视频网| 欧美一区二区三区啪啪| 欧美精品一区在线发布| 蜜臀av国产精品久久久久| 国产视频一区二区三区在线观看| 亚洲男人第一av网站| 欧美激情aaaa| 久久久久久久久久码影片| 欧美日本韩国一区二区三区| 猫咪成人在线观看| 国内一区二区三区| 午夜亚洲福利在线老司机| 一区二区欧美在线观看| 欧美大片一区二区| 欧美国产日韩精品| 在线日韩中文字幕| 久久综合九色综合欧美狠狠| 美女91精品| 亚洲第一区在线| 久久中文在线| 欧美成人精品激情在线观看| 黄色亚洲精品| 久久久久久尹人网香蕉| 久久久亚洲高清| 黄色成人在线网址| 久久手机精品视频| 亚洲风情在线资源站| 亚洲精品国久久99热| 欧美成年网站| 日韩视频在线一区二区| 亚洲综合日韩在线| 国产精品普通话对白| 欧美亚洲三级| 久久午夜精品一区二区| 国产主播一区二区| 久久一区免费| 亚洲精品乱码| 欧美中文字幕第一页| 国产日韩欧美在线看| 久久久亚洲国产天美传媒修理工| 欧美a级片网| 中日韩男男gay无套 | 欧美精品乱人伦久久久久久 | 久久国产精品色婷婷| 国产毛片精品视频| 久久经典综合| 亚洲欧洲日本专区| 欧美一区二区三区婷婷月色| 狠狠色2019综合网| 欧美国产视频日韩| 亚洲已满18点击进入久久| 久久精品欧美| 亚洲免费电影在线观看| 国产精品久久九九| 久久久久久亚洲精品杨幂换脸| 亚洲第一精品夜夜躁人人躁| 国产精品99久久久久久久久久久久 | 一区二区三区日韩在线观看| 国产精品福利网| 久久久亚洲国产天美传媒修理工| 日韩午夜黄色| 麻豆精品在线视频| 亚洲女同精品视频| 亚洲欧洲精品成人久久奇米网| 国产精品盗摄久久久| 国产欧美日韩不卡| 一本到高清视频免费精品| 久久国产乱子精品免费女| 亚洲品质自拍| 国产日韩一区二区三区在线播放| 蜜臀av在线播放一区二区三区| 亚洲性感激情| 91久久精品国产| 欧美波霸影院| 欧美在线观看日本一区| 99精品国产在热久久| 国产自产在线视频一区| 国产精品久久久久久户外露出 | 久久影院午夜论| 亚洲欧美www| 99香蕉国产精品偷在线观看| 欧美大尺度在线|