Java中對象的深複製(深克隆)和淺複製(淺克隆)之序列化

1.淺複製與深複製概念java

⑴淺複製(淺克隆) 工具

    被複制對象的全部變量都含有與原來的對象相同的值,而全部的對其餘對象的引用仍然指向原來的對象。換言之,淺複製僅僅複製所考慮的對象,而不復制它所引用的對象。  舉例說明:設計

常見的List的克隆方式有不少,下面咱們來列舉幾種常見的List淺複製的方式:code

public static void main(String []args){對象

       List<Map<String,String>> list1 = new ArrayList<Map<String, String>>();接口

       Map<String,String> map = new HashMap<String, String>();內存

       map.put("name", "xiaoming");get

       map.put("age", "28");it

       list1.add(map);io

       //克隆方法1:利用原list1做爲參數直接構造方法生成。

       List<Map<String,String>> list2 = new ArrayList<Map<String, String>>(list1);

        //克隆方法2:手動遍歷將原list1中的元素所有添加到複製表中。

       for(int i = 0, l = list1.size(); i < l; i++)

           list2.add(list1.get(i));   //克隆方法3:調用Collections的靜態工具方法 Collections.copy

//克隆方法4:使用System.arraycopy方法進行復制

    }

List自身是一個對象,他在存儲類類型的時候,只負責存儲地址。而存儲基本類型的時候,存儲的就是實實在在的值。縱然你有千千萬萬個List,元素仍是那麼幾個。不管是從新構造,Collections的複製方法,System的複製方法,仍是手動去遍歷,結果都同樣,這些方法都只改變了ArrayList對象的自己,簡單的添加了幾個指向老元素的地址。而沒作深層次的複製。(及壓根沒有沒有 new新對象 的操做出現。)

    有的時候咱們確實須要將這些元素也都複製下來而不是隻是用原來內存中的元素。List層實現這個問題。java語言設計之初就考慮進去了,避免操做這些埋在堆內存中的數據,全部操做都去針對能找到他們的地址。地址沒了自身還會被GC幹掉。因此只好一點點的去遍歷,new建立新的對象並賦予原來的值。聽說可能以爲上述的作法略微調整,因此巧用序列化對象讓這些數據在IO流中跑了一圈,能夠實現複製。其實把對象序列化到流中,java語言實在是妥協了,畢竟你不能再把地址扔進去吧?再說了io流是要和別的系統交互的,你發給別人一個地址讓別人去哪一個堆裏找?因此不用多提確定要新開闢堆內存的。

⑵深複製(深克隆)之序列化 

    被複制對象的全部變量都含有與原來的對象相同的值,除去那些引用其餘對象的變量。那些引用其餘對象的變量將指向被複制過的新對象,而再也不是原有的那些被引用的對象。換言之,深複製把要複製的對象所引用的對象都複製了一遍。 

Java中利用串行化來作深複製(深克隆)(避免重寫比較複雜對象的深複製的clone()方法,也能夠程序實現斷點續傳等等功能) 

 把對象寫到流裏的過程是串行化(Serilization)過程,可是在Java裏又很是形象地稱爲「冷凍」或者「醃鹹菜(picking)」過程;而把對象從流中讀出來的並行化(Deserialization)過程則叫作 「解凍」或者「回鮮(depicking)」過程。      應當指出的是,寫在流裏的是對象的一個拷貝,而原對象仍然存在於JVM裏面,所以「醃成鹹菜」的只是對象的一個拷貝,Java鹹菜還能夠回鮮。      在Java語言裏深複製一個對象,經常能夠先使對象實現Serializable接口,而後把對象(實際上只是對象的一個拷貝)寫到一個流裏(醃成鹹菜),再從流裏讀出來(把鹹菜回鮮),即可以重建對象。  以下爲深複製源代碼。

public List<Map<String,String>> deClone(Object obj) throws IOException,OptionalDataException,ClassNotFoundException{

//將對象寫到流裏

  ByteArrayOutoutStream bo=new ByteArrayOutputStream();

  ObjectOutputStream oo=new ObjectOutputStream(bo);

  oo.writeObject(obj);//從流裏讀出來

  ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());

  ObjectInputStream oi=new ObjectInputStream(bi);

  return(oi.readObject());

 }

這樣作的前提是對象以及對象內部全部引用到的對象都是可串行化的,不然,就須要仔細考察那些不可串行化的對象或屬性能否設成transient,從而將之排除在複製過程以外。

相關文章
相關標籤/搜索