2種方法實現java對象的深拷貝


2種方法實現java對象的深拷貝

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接: https://blog.csdn.net/caoxiaohong1005/article/details/78704890

 

1、如果一個類沒有實現Cloneable接口,直接調用clone()方法,會報異常CloneNotSupportedException,這一點已經在Object源碼中寫道:

 

  1.  
    * @return a clone of this instance.
  2.  
    * @exception CloneNotSupportedException if the object's class does not
  3.  
    * support the {@code Cloneable} interface. Subclasses
  4.  
    * that override the {@code clone} method can also
  5.  
    * throw this exception to indicate that an instance cannot
  6.  
    * be cloned.
  7.  
    * @see java.lang.Cloneable
  8.  
    */
  9.  
    protected native Object clone() throws CloneNotSupportedException;

 
          

 

 
          

 

而且,源碼也寫到Object的clone()方法是淺拷貝的,這一點在之前的Object源碼分析中我已經寫過了.

 
          

2、自定義類實現深拷貝方法有2種,下面依次給出具體寫法。

2.1、自定義類要實現Cloneable接口,並覆寫clone()方法。

 

 

  1.  
    /**
  2.  
    * 深拷貝和淺拷貝的測試
  3.  
    */
  4.  
    //測試類1
  5.  
    class Person implements Cloneable{
  6.  
    String name;
  7.  
    int age;
  8.  
    Person(String name, int age){
  9.  
    this.name=name;
  10.  
    this.age=age;
  11.  
    }
  12.  
    @Override
  13.  
    public Object clone() {
  14.  
    try{
  15.  
    return super.clone();
  16.  
    } catch(CloneNotSupportedException e){
  17.  
    return null;
  18.  
    }
  19.  
    }
  20.  
    }
  21.  
    //測試類2
  22.  
     
  23.  
    class Animal implements Cloneable{
  24.  
    Person host; //主人
  25.  
    int age;//年紀
  26.  
    Animal(Person person, int age){
  27.  
    this.host=person;
  28.  
    this.age=age;
  29.  
    }
  30.  
    @Override
  31.  
    public Object clone(){
  32.  
    try{
  33.  
    Animal animal=(Animal) super.clone();
  34.  
    animal.host=(Person)host.clone(); //深拷貝處理
  35.  
    return animal;
  36.  
    } catch (CloneNotSupportedException e){
  37.  
    return null;
  38.  
    }
  39.  
    }
  40.  
    }
  41.  
     
  42.  
    //測試
  43.  
    public class Main{
  44.  
    public static void main(String[] args) {
  45.  
    Person person1= new Person("cxh",26);
  46.  
    Person person2=(Person)person1.clone();
  47.  
    System.out.println( "----------------淺拷貝--------------");
  48.  
    //測試Object的clone方法為淺拷貝
  49.  
    //String類用==測試內存地址是否一致
  50.  
    System.out.println( "person1和person2的name內存地址是否相同:"+(person1.name==person2.name));
  51.  
     
  52.  
     
  53.  
     
  54.  
    System.out.println( "----------------深拷貝--------------");
  55.  
    //重寫Object的clone方法,實現深拷貝
  56.  
    //還是用==查看兩個對象的內存地址是否相等來確定是否為兩個對象,如果是兩個內存地址,那么就是深拷貝
  57.  
    Animal animal1= new Animal(new Person("cxh",26),3);
  58.  
    Animal animal2=(Animal) animal1.clone();
  59.  
    System.out.println( "animal1和animal2的host內存地址是否相同:"+(animal1.host==animal2.host));
  60.  
    }
  61.  
    }

輸出:
 
          

 

 

 

  1.  
    ----------------淺拷貝--------------
  2.  
    person1和person2的name內存地址是否相同: true
  3.  
    ----------------深拷貝--------------
  4.  
    animal1和animal2的host內存地址是否相同: false
  5.  
     
  6.  
    Process finished with exit code 0

 

一個講解很詳細的博客:http://blog.csdn.net/zhangjg_blog/article/details/18369201


 
          

 

2.2、通過序列化方式實現深拷貝:先將要拷貝對象寫入到內存中的字節流中,然后再從這個字節流中讀出剛剛存儲的信息,作為一個新對象返回,那么這個新對象和原對象就不存在任何地址上的共享,自然實現了深拷貝。

自定義類需要實現Serializable接口。

 

  1.  
    import java.io.*;
  2.  
     
  3.  
    /**
  4.  
    * 深拷貝和淺拷貝的測試
  5.  
    * 如何利用序列化來完成對象的拷貝呢?在內存中通過字節流的拷貝是比較容易實現的。把母對象寫入到一個字節流中,再從字節流中將其讀出來,
  6.  
    * 這樣就可以創建一個新的對象了,並且該新對象與母對象之間並不存在引用共享的問題,真正實現對象的深拷貝。
  7.  
    */
  8.  
    //工具類
  9.  
    class CloneUtil{
  10.  
    public static <T extends Serializable> T clone(T obj){
  11.  
    T cloneObj= null;
  12.  
    try{
  13.  
    //寫入字節流
  14.  
    ByteArrayOutputStream baos= new ByteArrayOutputStream();
  15.  
    ObjectOutputStream oos= new ObjectOutputStream(baos);
  16.  
    oos.writeObject(obj);
  17.  
    oos.close();
  18.  
     
  19.  
    //分配內存,寫入原始對象,生成新對象
  20.  
    ByteArrayInputStream bais= new ByteArrayInputStream(baos.toByteArray());//獲取上面的輸出字節流
  21.  
    ObjectInputStream ois= new ObjectInputStream(bais);
  22.  
     
  23.  
    //返回生成的新對象
  24.  
    cloneObj=(T)ois.readObject();
  25.  
    ois.close();
  26.  
    } catch (Exception e){
  27.  
    e.printStackTrace();
  28.  
    }
  29.  
    return cloneObj;
  30.  
    }
  31.  
    }
  32.  
     
  33.  
    //測試類1
  34.  
    class Person implements Serializable{
  35.  
    String name;
  36.  
    int age;
  37.  
    Person(String name, int age){
  38.  
    this.name=name;
  39.  
    this.age=age;
  40.  
    }
  41.  
     
  42.  
    }
  43.  
    //測試類2
  44.  
     
  45.  
    class Animal implements Serializable{
  46.  
    Person host; //主人
  47.  
    int age;//年紀
  48.  
    Animal(Person person, int age){
  49.  
    this.host=person;
  50.  
    this.age=age;
  51.  
    }
  52.  
    }
  53.  
     
  54.  
     
  55.  
    //測試
  56.  
    public class Main{
  57.  
    public static void main(String[] args) {
  58.  
    System.out.println( "----------------深拷貝--------------");
  59.  
    //重寫Object的clone方法,實現深拷貝
  60.  
    //還是用==查看兩個對象的內存地址是否相等來確定是否為兩個對象,如果是兩個內存地址,那么就是深拷貝
  61.  
    Animal animal1= new Animal(new Person("cxh",26),3);
  62.  
    Animal animal2=CloneUtil.clone(animal1);
  63.  
    System.out.println( "animal1和animal2的host內存地址是否相同:"+(animal1.host==animal2.host));
  64.  
    }
  65.  
    }

輸出結果:

 

 

  1.  
    ----------------深拷貝--------------
  2.  
    animal1和animal2的host內存地址是否相同: false

參考博客: http://blog.csdn.net/chenssy/article/details/12952063


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM