【JavaSE】一文搞懂Java深拷贝和浅拷贝

前言

首先,所谓深拷贝浅拷贝是针对引用类型来说的。在谈深拷贝、浅拷贝之前,要先简单了解一下Java内存模型,知道不同数据数据在内存中的分配原理,才能更好的理解深拷贝和浅拷贝是什么意思。
以下为摘自《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》介绍:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

定义

有了以上了解后,我们可以知道,对应引用类型来说,栈中存放的只是对象的引用,起具体的数据是指向堆中的对象实例数据的,就想你手中的银行卡只是一个引用,它对应的是银行的账户,账户上面是你的存款,通过银行卡可以对账号进行一系列的操作。

浅拷贝:仅拷贝栈中的变量引用,两个引用指向堆中的同一个对象实例数据。
相当于浅拷贝只是复制了一个副卡出来,副卡和主卡是对应的同一个账号,一个卡支付了一笔钱,另一个卡查的余额一定是同步变化的。

深拷贝:在堆中的新建一个对象实例,将源对象实例数据复制到新的对象实例中,拷贝的对象指向新的对象实例数据,互相独立,互不影响。
相当于深拷贝不仅是复制了一个卡出来,还同步新开了一个账户,账户里存了跟主卡一样的(币种、金额)存款,一个卡的支出和收入对另一个卡完全没有影响。

示意图如下:

在这里插入图片描述


在这里插入图片描述

浅拷贝验证

String类型/基本类型/包装类型

在这里插入图片描述1. 源对象的值变了之后,对拷贝对象无任何影响
2. 断言源对象和拷贝对象也不是同一个引用

引用类型

在这里插入图片描述

  1. 断言两个对象的A a 属性是同一个引用对象,测试通过
  2. 通过控制台打印的结果也可以看出来,原始对象的修改,影响到了拷贝对象

深拷贝实现

不管用什么方式,只要保证复制出来的新对象,在堆中的实例数据是独立的即可。

重载clone方法-不建议!

众多公认的规范中,都对重写clone方法比较慎重,本文也不提供该方式的示例,如果确实需要,网上很容易查到相关的demo代码。或者《Effective Java》中有大量demo演示了如何正确使用clone方法
罗列两个相关的代码规范:

1、《Java开发手册(黄山版)》中约定:

25.【推荐】慎用 Object 的 clone 方法来拷贝对象。
说明:对象 clone 方法默认是浅拷贝,若想实现深拷贝需覆写 clone 方法实现域对象的深度遍历式拷贝。

2、《Effective Java》中也明确指出谨慎的覆盖clone方法

在这里插入图片描述

构造函数

对复制对象的引用类型属性(字段),通过new的方式来创建新的引用对象,将源对象的值复制给new的对象,保证复制对象和源对象拥有独立的对象实例即可。如上文图例中的深拷贝示意图``deepCopyRef()方法

反序列化-建议

在这里插入图片描述

深拷贝工具类

MapStruct

使用很简单,只需要写个类,通过注解方式声名映射关系即可,官方提供的非常丰富的使用示例。

官方开源地址: https://github.com/mapstruct/mapstruct
官方demo: https://github.com/mapstruct/mapstruct-examples

示例代码

https://gitee.com/qbhj/java-cases/tree/master/case-javase-deepcopy

参考资料

  1. 《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》-周志明
  2. 《Effective Java中文版第2版》-Joshua Bloch
  3. 《Java开发手册(黄山版)》
  4. MapStruct

猜你喜欢

转载自blog.csdn.net/weixin_43582081/article/details/129188043