0x01:概述

Java中的对象拷贝 ( Object Copy ) 是指将一个对象的所有属性(成员变量)拷贝到另一个有着相同类类型的对象中去。例如,对象 A 和对象 B 都属于类 S,具有属性 a 和 b。那么对对象 A 进行拷贝操作赋值给对象 B 就是:

B.a = A.a;

B.b = A.b;

拷贝对象是很常见的,主要是为了在新的上下文环境中复用现有对象的部分或全部数据。Java中的对象拷贝主要分为

浅拷贝( Shallow Copy )

深拷贝( Deep Copy )

Java中的数据类型分为基本数据类型和引用数据类型。对于这两种数据类型,在进行赋值操作、用作方法参数或返回值时,会有值传递和引用(地址)传递的差别。

浅拷贝(Shallow Copy)

对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。

对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值。

具体模型如下图所示,可以看到基本数据类型的成员变量,对其值创建了新的拷贝;而引用数据类型的成员变量的实例仍然是只有一份,两个对象的该成员变量都指向同一个实例。

0x02:浅拷贝的实现方式

拷贝构造方法实现浅拷贝

拷贝构造方法指的是该类的构造方法参数为该类的对象。使用拷贝构造方法可以很好地完成浅拷贝,直接通过一个现有的对象创建出与该对象属性相同的新的对象。

重写clone()方法进行浅拷贝

Object类是类结构的根类,其中有一个方法

protected Object clone() throws CloneNotSupportedException

这个方法就是进行的浅拷贝。有了这个浅拷贝模板,可以通过调用clone()方法来实现对象的浅拷贝。但是需要注意:

(1)Object类虽然有这个方法,但是这个方法是受保护的(被protected修饰),所以无法直接使用。

(2)使用clone方法的类必须实现Cloneable接口,否则会抛出异常CloneNotSupportedException。

对于这两点,我们的解决方法是:在要使用clone方法的类中重写clone()方法,通过super.clone()调用Object类中的原clone方法。

0x03:深拷贝的实现方式

首先介绍对象图的概念。设想一下,一个类有一个对象,其成员变量中又有一个对象,该对象指向另一个对象,另一个对象又指向另一个对象,直到一个确定的实例。这就形成了对象图。那么对于深拷贝来说,不仅要复制对象的所有基本数据类型的成员变量值,还要为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象图进行拷贝。

一句话,深拷贝对引用数据类型的成员变量的对象图中所有的对象都开辟了内存空间;而浅拷贝只是传递地址指向,新的对象并没有对引用数据类型创建内存空间。深拷贝模型如下图所示,可以看到所有的成员变量都进行了复制。

因为创建内存空间和拷贝整个对象图,所以深拷贝相比于浅拷贝速度较慢并且花销较大。

重写clone方法来实现深拷贝

与通过重写clone方法实现浅拷贝的基本思路一样,只需要为对象图的每一层的每一个对象都实现Cloneable接口并重写clone方法,最后在最顶层的类的重写的clone方法中调用所有的clone方法即可实现深拷贝。简单的说只要每一层的每个对象都进行浅拷贝,就等于实现了深拷贝。

@Override

public Object clone() {

//深拷贝

try {

// 直接调用父类的clone()方法

Student student = (Student) super.clone();

student.引用对象 = (引用对象) 引用对象.clone();

return student;

} catch (CloneNotSupportedException e) {

return null;

}

}

对象序列化实现深拷贝

虽然层次调用clone方法可以实现深拷贝,但是显然代码量实在太大。特别对于属性数量比较多、层次比较深的类而言,每个类都要重写clone方法太过繁琐。将对象序列化为字节序列后,默认会将该对象的整个对象图进行序列化,再通过反序列即可完美地实现深拷贝。

//将对象写入流中

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);

objectOutputStream.writeObject(拷贝对象);

//从流中取出

ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());

ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);

return (拷贝对象)objectInputStream.readObject();

JSON或者XML方式实现深拷贝

因为一个POJO对象可以通过JSON库变成一个json字符串(通过XML库变成一个xml字符串),再通过对应的类库又反序列化成另外一个完整的对象。

String json =JSON.toJSONString(src);

T object = JSON.parseObject(json, clazz);

mysql浅拷贝_深入理解浅拷贝和深拷贝相关推荐

  1. python怎么避免浅拷贝_详谈Python中的深拷贝和浅拷贝

    在平时工作中,经常涉及到数据的传递,在数据传递使用过程中,可能会发生数据被修改的问题.为了防止数据被修改,就需要在传递一个副本,即使副本被修改,也不会影响原数据的使用.为了生成这个副本,就产生了拷贝. ...

  2. 深入理解mysql系列_深入理解MySQL系列之锁

    按锁思想分类 悲观锁 优点:适合在写多读少的并发环境中使用,虽然无法维持非常高的性能,但是在乐观锁无法提更好的性能前提下,可以做到数据的安全性 缺点:加锁会增加系统开销,虽然能保证数据的安全,但数据处 ...

  3. 简单理解mysql事务_如何理解数据库事务中的一致性的概念?

    比较支持@Kai Peng 的答案,只是缺少例子说明. 而其他一些人的答案甚至有明显的错误.最近正好也在研究这方面的东西,不算是回答,就是跟大家讨论讨论. 首先,我们需要搞清楚为什么会出现事务.[1] ...

  4. java mysql索引_如何理解并正确使用MySql索引

    1.概述 索引是存储引擎用于快速查找记录的一种数据结构,通过合理的使用数据库索引可以大大提高系统的访问性能,接下来主要介绍在MySql数据库中索引类型,以及如何创建出更加合理且高效的索引技巧. 注:这 ...

  5. clone是深拷贝还是浅拷贝_Cloneable接口的作用与探索理解浅拷贝与深拷贝

    导读:本文将主要讨论设计模式--原型模式中,关于cloneable接口及浅拷贝与深拷贝的概念. 原型模式的理解 关于原型模式的理解,我在网上发现一个有趣且助于理解原型模式的例子在这里分享一下:火影忍者 ...

  6. python怎么避免浅拷贝_深度解读Python深拷贝与浅拷贝问题

    Illustrations by Leon Tukker ♚ 作者:PayneLi,Python全家桶,主要讲述数据挖掘.机器学习和深度学习领域的前沿技术,同时还会推荐一些行业最新论文.技术专家的经验 ...

  7. 对深拷贝与浅拷贝的再次理解

    对深拷贝与浅拷贝的再次理解 记得11年底找工作的时候,面试时曾经遇到有面试官问的对深拷贝与浅拷贝的理解,那时候自己回来查了资料,写了篇博客,感觉自己理解了,其实理解的不深刻,最近在调试bug的时候,再 ...

  8. 理解浅拷贝和深拷贝以及实现方法

    一.数据类型 数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和引用数据类型Object,包含(function,Array,Da ...

  9. 浅拷贝 python_python中的浅拷贝和深拷贝

    http://python.jobbole.com/82294/ Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介 ...

最新文章

  1. linux中system清屏命令,Linux磁盘管理命令
  2. Android 适配底部返回键等虚拟键盘的完美解决方案
  3. 关于Redis的数据迁移(三种方法)
  4. Spring-AOP实践 - 统计访问时间
  5. 为什么能通过域成员主机拿下域控服务器的密码呢
  6. mysql xtrabackup-v2_pxc wsrep_sst_method均配置为xtrabackup-v2报错
  7. 【图片识别】java 图片文字识别 ocr (转)
  8. 一些dos下简单命令
  9. 天池 在线编程 音乐组合
  10. ios开发 多人语音聊天_在 Unity 多人游戏中实现语音对话
  11. 15-mysql-进阶九-联合查询
  12. java 度量_Java度量方法调用率
  13. 自用迷你版的Deferred
  14. 凸优化第六章逼近与拟合 6.2 最小范数问题
  15. 开源项目管理软件产品对比分析资料整理
  16. 单片机STM8S测量电压电路_50个单片机晶振问题及解决方法小结
  17. WIFI6 5G信道、频宽对应关系
  18. 微信公众号添加html,微信公众号添加页面模板怎么开通?
  19. Adobe Photoshop CC 2019( adobe ps cc)果然不一般
  20. win10计算机不分区,win10系统自带无损分区且数据不丢失的处理方案

热门文章

  1. 你眼中的嵌入式是什么样?
  2. 再聊机器人设计:如何加速开发流程?
  3. 电子设计竞赛电源题(2)-检波与采样
  4. pytorch 转换onnx_新版PyTorch发布!新增TorchScript API,扩展ONNX导出
  5. java中demo接人_return的用法_如何理解java中return的用法?
  6. 怎么拿img标签的data_PASCAL VOC数据集-分割标签索引颜色对照及程序
  7. P4016 负载平衡问题(最小费用最大流)
  8. Vue.js(17)之 插槽
  9. div根据滑动页面位置显示
  10. 基于chrome内核的.NET开发资源