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

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

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

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

2种方法实现java对象的深拷贝的更多相关文章

  1. JAVA写JSON的三种方法,java对象转json数据

    JAVA写JSON的三种方法,java对象转json数据 转自:http://www.xdx97.com/#/single?bid=5afe2ff9-8cd1-67cf-e7bc-437b74c07a ...

  2. 两个变量交换的四种方法(Java) 七种方法(JS)

    两个变量交换的四种方法(Java)   对于两种变量的交换,我发现四种方法,下面我用Java来演示一下. 1.利用第三个变量交换数值,简单的方法. (代码演示一下) 1 class TestEV 2 ...

  3. 三种方法获取Class对象的区别

    有关反射的内容见 java反射 得到某个类的Class对象有三种方法: 使用“类名.class”取得 Class.forName(String className) 通过该类实例对象的getClass ...

  4. 两个变量交换的四种方法(Java)

    对于两种变量的交换,我发现四种方法,下面我用Java来演示一下. 1.利用第三个变量交换数值,简单的方法. (代码演示一下) class TestEV //创建一个类 { public static ...

  5. Hibernate,Session方法使得java对象进入持久化状态;持久化对象特征

    以下情况java对象进入持久化状态: session.save()方法把临时对象转变为持久化对象. session.load()和session.get()方法得到的对象总是处于持久化状态. sess ...

  6. 数组k平移三种方法(java)

    上代码,本文用了三种方法实现,时间复杂度不一样,空间复杂度都是o(1): public class ArrayKMove { /** * 问题:数组的向左k平移,k小于数组长度 * @param ar ...

  7. 五种方法实现Java的Singleton单例模式

    面试的时候经常会问到Java的单例模式,这道题能很好的考察候选人对知识点的理解程度.单例模式要求在系统运行时,只存在唯一的一个实例对象. 下面我们来详细剖析一下其中的关键知识点,并介绍五种实现方法,以 ...

  8. Top k问题的讨论(三种方法的java实现及适用范围)

    在很多的笔试和面试中,喜欢考察Top K.下面从自身的经验给出三种实现方式及实用范围. 合并法 这种方法适用于几个数组有序的情况,来求Top k.时间复杂度为O(k*m).(m:为数组的个数).具体实 ...

  9. 三种方法实现java调用Restful接口

    1,基本介绍 Restful接口的调用,前端一般使用ajax调用,后端可以使用的方法比较多, 本次介绍三种: 1.HttpURLConnection实现 2.HttpClient实现 3.Spring ...

随机推荐

  1. HAOI2010软件安装

    首先tarjan缩点应该能看出来,然后我用topsort跑了个DAG上的一维dp,结果WA的很惨. 其实用DAG应该也能做,但是DAG强调整体顺序,而对一些局部问题,例如两个儿子怎么分配,是否给当前节 ...

  2. y7000笔记本 darknet-yolo安装与测试(Ubuntu16.04+Cuda9.0+Cudnn7.1)

    https://zhuanlan.zhihu.com/p/41096599 1.先查看是否安装有以下组件,若有先考虑彻底删除再安装(安装严格按照下面顺序进行) 查看nvidia 版本 nvidia-s ...

  3. 梯度下降(Gradient Descent)小结 -2017.7.20

    在求解算法的模型函数时,常用到梯度下降(Gradient Descent)和最小二乘法,下面讨论梯度下降的线性模型(linear model). 1.问题引入 给定一组训练集合(training se ...

  4. 一些有意思的git

    fs: https://github.com/psankar/simplefs https://github.com/gzc/isystem/blob/master/basic/Crash_Consi ...

  5. Dropdown 下拉菜单

    将动作或菜单折叠到下拉菜单中. 基础用法 移动到下拉菜单上,展开更多操作. 通过组件slot来设置下拉触发的元素以及需要通过具名slot为dropdown 来设置下拉菜单.默认情况下,下拉按钮只要ho ...

  6. 解决FTP服务器上中文名文件下载后为空的问题

    转: 解决FTP服务器上中文名文件下载后为空的问题 2017年07月20日 15:19:21 代码的寂寞 阅读数 2428  版权声明:本文为博主原创文章,未经博主允许不得转载. https://bl ...

  7. 小D课堂 - 新版本微服务springcloud+Docker教程_3-02CAP理论知识

    笔记 2.分布式应用知识CAP理论知识     简介:讲解分布式核心知识CAP理论 CAP定理:             指的是在一个分布式系统中,Consistency(一致性). Availabi ...

  8. 小D课堂 - 新版本微服务springcloud+Docker教程_2_04微服务下电商项目基础模块设计

    笔记 4.微服务下电商项目基础模块设计     简介:微服务下电商项目基础模块设计 分离几个模块,课程围绕这个基础项目进行学习             小而精的方式学习微服务 1.用户服务       ...

  9. Spring Boot Application后台守护Daemon应用

    本地代码启动不报错,部署到服务器之后出现如下一个错误. 系统的日志如下: Error starting ApplicationContext. To display the conditions re ...

  10. python 类中__int__和__str__的使用

    class F: def __str__(self): return 'hello china' def __int__(self): return 123 res = F()print(res) # ...