2种方法实现java对象的深拷贝

2022-12-13,,,

2种方法实现java对象的深拷贝

2017年12月03日 22:23:07 iCoding91 阅读数 4420更多

分类专栏: java

 

版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/caoxiaohong1005/article/details/78704890

1、如果一个类没有实现Cloneable接口,直接调用clone()方法,会报异常CloneNotSupportedException,这一点已经在Object源码中写道:

     

    * @return a clone of this instance.

     

    * @exception CloneNotSupportedException if the object's class does not

     

    * support the {@code Cloneable} interface. Subclasses

     

    * that override the {@code clone} method can also

     

    * throw this exception to indicate that an instance cannot

     

    * be cloned.

     

    * @see java.lang.Cloneable

     

    */

     

    protected native Object clone() throws CloneNotSupportedException;



而且,源码也写到Object的clone()方法是浅拷贝的,这一点在之前的Object源码分析中我已经写过了.


2、自定义类实现深拷贝方法有2种,下面依次给出具体写法。

2.1、自定义类要实现Cloneable接口,并覆写clone()方法。

     

    /**

     

    * 深拷贝和浅拷贝的测试

     

    */

     

    //测试类1

     

    class Person implements Cloneable{

     

    String name;

     

    int age;

     

    Person(String name,int age){

     

    this.name=name;

     

    this.age=age;

     

    }

     

    @Override

     

    public Object clone() {

     

    try{

     

    return super.clone();

     

    }catch(CloneNotSupportedException e){

     

    return null;

     

    }

     

    }

     

    }

     

    //测试类2

     
     
     

    class Animal implements Cloneable{

     

    Person host;//主人

     

    int age;//年纪

     

    Animal(Person person,int age){

     

    this.host=person;

     

    this.age=age;

     

    }

     

    @Override

     

    public Object clone(){

     

    try{

     

    Animal animal=(Animal) super.clone();

     

    animal.host=(Person)host.clone();//深拷贝处理

     

    return animal;

     

    }catch (CloneNotSupportedException e){

     

    return null;

     

    }

     

    }

     

    }

     
     
     

    //测试

     

    public class Main{

     

    public static void main(String[] args) {

     

    Person person1=new Person("cxh",26);

     

    Person person2=(Person)person1.clone();

     

    System.out.println("----------------浅拷贝--------------");

     

    //测试Object的clone方法为浅拷贝

     

    //String类用==测试内存地址是否一致

     

    System.out.println("person1和person2的name内存地址是否相同:"+(person1.name==person2.name));

     
     
     
     
     
     
     

    System.out.println("----------------深拷贝--------------");

     

    //重写Object的clone方法,实现深拷贝

     

    //还是用==查看两个对象的内存地址是否相等来确定是否为两个对象,如果是两个内存地址,那么就是深拷贝

     

    Animal animal1=new Animal(new Person("cxh",26),3);

     

    Animal animal2=(Animal) animal1.clone();

     

    System.out.println("animal1和animal2的host内存地址是否相同:"+(animal1.host==animal2.host));

     

    }

     

    }

输出:


     

    ----------------浅拷贝--------------

     

    person1和person2的name内存地址是否相同:true

     

    ----------------深拷贝--------------

     

    animal1和animal2的host内存地址是否相同:false

     
     
     

    Process finished with exit code 0

一个讲解很详细的博客:http://blog.csdn.net/zhangjg_blog/article/details/18369201


2.2、通过序列化方式实现深拷贝:先将要拷贝对象写入到内存中的字节流中,然后再从这个字节流中读出刚刚存储的信息,作为一个新对象返回,那么这个新对象和原对象就不存在任何地址上的共享,自然实现了深拷贝。

自定义类需要实现Serializable接口。

     

    import java.io.*;

     
     
     

    /**

     

    * 深拷贝和浅拷贝的测试

     

    * 如何利用序列化来完成对象的拷贝呢?在内存中通过字节流的拷贝是比较容易实现的。把母对象写入到一个字节流中,再从字节流中将其读出来,

     

    * 这样就可以创建一个新的对象了,并且该新对象与母对象之间并不存在引用共享的问题,真正实现对象的深拷贝。

     

    */

     

    //工具类

     

    class CloneUtil{

     

    public static <T extends Serializable> T clone(T obj){

     

    T cloneObj=null;

     

    try{

     

    //写入字节流

     

    ByteArrayOutputStream baos=new ByteArrayOutputStream();

     

    ObjectOutputStream oos=new ObjectOutputStream(baos);

     

    oos.writeObject(obj);

     

    oos.close();

     
     
     

    //分配内存,写入原始对象,生成新对象

     

    ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());//获取上面的输出字节流

     

    ObjectInputStream ois=new ObjectInputStream(bais);

     
     
     

    //返回生成的新对象

     

    cloneObj=(T)ois.readObject();

     

    ois.close();

     

    }catch (Exception e){

     

    e.printStackTrace();

     

    }

     

    return cloneObj;

     

    }

     

    }

     
     
     

    //测试类1

     

    class Person implements Serializable{

     

    String name;

     

    int age;

     

    Person(String name,int age){

     

    this.name=name;

     

    this.age=age;

     

    }

     
     
     

    }

     

    //测试类2

     
     
     

    class Animal implements Serializable{

     

    Person host;//主人

     

    int age;//年纪

     

    Animal(Person person,int age){

     

    this.host=person;

     

    this.age=age;

     

    }

     

    }

     
     
     
     
     

    //测试

     

    public class Main{

     

    public static void main(String[] args) {

     

    System.out.println("----------------深拷贝--------------");

     

    //重写Object的clone方法,实现深拷贝

     

    //还是用==查看两个对象的内存地址是否相等来确定是否为两个对象,如果是两个内存地址,那么就是深拷贝

     

    Animal animal1=new Animal(new Person("cxh",26),3);

     

    Animal animal2=CloneUtil.clone(animal1);

     

    System.out.println("animal1和animal2的host内存地址是否相同:"+(animal1.host==animal2.host));

     

    }

     

    }

输出结果:

     

    ----------------深拷贝--------------

     

    animal1和animal2的host内存地址是否相同:false

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

2种方法实现java对象的深拷贝的相关教程结束。