java -- 深拷贝和浅拷贝的区别 如何实现深拷贝和浅拷贝
文章目录
- 1. 深拷贝和浅拷贝的区别
- 1.1 浅拷贝实例
- 1.1.1 测试1 直接赋值
- 1.1.2 测试2 改变源对象的值
- 1.2 深拷贝实例
- `这是用于深拷贝的测试类`
- 1.2.1 方法一: 构造函数
- 1.2.2 方法二: 重载clone()方法
- 1.2.3 方法三:Apache Commons Lang序列化
- 1.2.4 方法四:Gson
- `Gson可以将对象序列化成JSON,也可以将JSON反序列化成对象,所以我们可以用它进行深拷贝。`
- 1.2.5 方法五: Jackson序列化
- `Jackson与Gson相似,可以将对象序列化成JSON,明显不同的地方是拷贝的类(包括其成员变量)需要有默认的无参构造函数`
- 1.2.6 小结
1. 深拷贝和浅拷贝的区别
- 浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。
- 深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。
深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。
假设B复制了A,修改A的时候,看B是否发生变化:
如果B跟着也变了,说明是浅拷贝(修改堆内存中的同一个值)
如果B没有改变,说明是深拷贝(修改堆内存中的不同的值)
- 浅拷贝(shallowCopy)只是增加了一个指针指向已存在的内存地址,
- 深拷贝(deepCopy)是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存。
- 深拷贝是指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。
- 使用深拷贝的情况下,释放内存的时候不会因为出现浅拷贝时释放同一个内存的错误。
1.1 浅拷贝实例
1.1.1 测试1 直接赋值
public class Student {private String name;public Student(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public static void main(String[] args) {Student student1 = new Student("Tom");Student student2 = student1;// 因为是指向同一个地址 所以结果必然是相同的System.out.println(student1 == student2);}
}
1.1.2 测试2 改变源对象的值
public class Student {private String name;public Student(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}public static void main(String[] args) {Student student1 = new Student("Tom");Student student2 = student1;student1.setName("Jack");System.out.println(student2.getName());}
}
运行结果:
1.2 深拷贝实例
这是用于深拷贝的测试类
public class Student {private String name;public Student(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
1.2.1 方法一: 构造函数
@org.junit.Testpublic void constructorCopy() {// 被克隆的类Student xiaoMing = new Student("小明");
// 调用构造函数时进行深拷贝Student cloneStudent = new Student(xiaoMing.getName());System.out.println(xiaoMing == cloneStudent); // false}
1.2.2 方法二: 重载clone()方法
Object类有个clone()的拷贝方法,不过它是protected类型的,我们需要重写它并修改为public类型。除此之外,子类还需要实现Cloneable接口来告诉JVM这个类是可以拷贝的。
让我们修改一下Student类,实现Cloneable接口,使其支持深拷贝。
Student.java
public class Student implements Cloneable {private String name;public Student(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}// 重写克隆方法@Overridepublic Student clone() throws CloneNotSupportedException {return (Student) super.clone();}
}
测试:
@org.junit.Testpublic void coneableCopy() throws CloneNotSupportedException {// 被克隆的类Student xiaoMing = new Student("小明");Student cloneStudent = xiaoMing.clone();System.out.println(xiaoMing == cloneStudent);}
1.2.3 方法三:Apache Commons Lang序列化
Java提供了序列化的能力,我们可以先将源对象进行序列化,再反序列化生成拷贝对象。但是,使用序列化的前提是拷贝的类(包括其成员变量)需要实现Serializable接口。Apache Commons Lang包对Java序列化进行了封装,我们可以直接使用它。
第一步:导入依赖
pom.xml
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version>
</dependency>
第二步:让我们修改一下Student类,实现Serializable接口,使其支持序列化。
public class Student implements Serializable {private String name;public Student(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
测试:
@org.junit.Testpublic void coneableCopy() throws CloneNotSupportedException {// 被克隆的类Student xiaoMing = new Student("小明");// 使用Apache Commons Lang序列化进行深拷贝Student copyStudent = (Student) SerializationUtils.clone(xiaoMing);System.out.println(xiaoMing == copyStudent);}
1.2.4 方法四:Gson
Gson可以将对象序列化成JSON,也可以将JSON反序列化成对象,所以我们可以用它进行深拷贝。
第一步:导入依赖
pom.xml
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.5</version>
</dependency>
第二步: 修改一下Student类,实现Serializable接口,使其支持序列化。同上
测试:
@org.junit.Testpublic void coneableCopy() throws CloneNotSupportedException {// 被克隆的类Student xiaoMing = new Student("小明");// 使用Gson序列化进行深拷贝Gson gson = new Gson();Student copyStudent = gson.fromJson(gson.toJson(xiaoMing), Student.class);System.out.println(xiaoMing == copyStudent);}
1.2.5 方法五: Jackson序列化
Jackson与Gson相似,可以将对象序列化成JSON,明显不同的地方是拷贝的类(包括其成员变量)需要有默认的无参构造函数
第一步:导入依赖
pom.xml
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.12.3</version></dependency>
第二步:让我们修改一下Student类,实现默认的无参构造函数,使其支持Jackson。
Student.java
package com.tian.pojo;import java.io.Serializable;/*** ClassName: Student* Description:** @author Tianjiao* @date 2021/5/30 18:12*/
public class Student implements Serializable {private String name;// 实现无参构造方法public Student() {}public Student(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
测试:
@org.junit.Testpublic void coneableCopy() throws CloneNotSupportedException, JsonProcessingException {// 被克隆的类Student xiaoMing = new Student("小明");// 使用Jackson序列化进行深拷贝ObjectMapper objectMapper = new ObjectMapper();Student copyStudent = objectMapper.readValue(objectMapper.writeValueAsString(xiaoMing), Student.class);System.out.println(xiaoMing == copyStudent);}
1.2.6 小结
深拷贝方法 | 优点 | 缺点 |
---|---|---|
构造函数 | 1. 底层实现简单 2. 不需要引入第三方包 3. 系统开销小 4. 对拷贝类没有要求,不需要实现额外接口和方法 | 1. 可用性差,每次新增成员变量都需要新增新的拷贝构造函数 |
重载clone()方法 | 1. 底层实现较简单 2. 不需要引入第三方包 3. 系统开销小 | 1. 可用性较差,每次新增成员变量可能需要修改clone()方法 2. 拷贝类(包括其成员变量)需要实现Cloneable接口 |
Apache Commons Lang序列化 | 1. 可用性强,新增成员变量不需要修改拷贝方法 | 1. 底层实现较复杂 2. 需要引入Apache Commons Lang第三方JAR包 3. 拷贝类(包括其成员变量)需要实现Serializable接口 4. 序列化与反序列化存在一定的系统开销 |
Gson序列化 | 1. 可用性强,新增成员变量不需要修改拷贝方法 2. 对拷贝类没有要求,不需要实现额外接口和方法 | 1. 底层实现复杂 2. 需要引入Gson第三方JAR包 3. 序列化与反序列化存在一定的系统开销 |
Jackson序列化 | 1. 可用性强,新增成员变量不需要修改拷贝方法 | 1. 底层实现复杂 2. 需要引入Jackson第三方JAR包 3. 拷贝类(包括其成员变量)需要实现默认的无参构造函数 4. 序列化与反序列化存在一定的系统开销 |
java -- 深拷贝和浅拷贝的区别 如何实现深拷贝和浅拷贝相关推荐
- java深入理解深拷贝和浅拷贝的区别 如何实现深拷贝和浅拷贝
文章目录 一.拷贝简介 1.1 引用拷贝 1.2 对象拷贝 二.浅拷贝 2.1 定义 三.深拷贝 3.1 定义 一.拷贝简介 1.1 引用拷贝 创建一个指向对象的引用变量的拷贝 public clas ...
- Java基础-深拷贝和浅拷贝的区别
深拷贝与浅拷贝 一般来说,拷贝的类型分为 深拷贝与浅拷贝. |-----------------------------| | 深拷贝:引用对象的值等信息,复制一份一样的. | ...
- 如何完美解答面试问题——深拷贝和浅拷贝的区别
大家好,我是孤焰.今天要谈一谈在面试过程中可能被面试官提到的一个问题--深拷贝和浅拷贝的区别? 由于我也是刚刚学习编程的小白,所以此篇博文将参考了多篇博文,最后总结而成. 最近由于多门考试临近,所以博 ...
- Python基础:对象的深拷贝和浅拷贝的区别
Python基础:对象的深拷贝和浅拷贝的区别 1 变量与对象 2 不可变对象与可变对象 3 直接赋值 4 浅拷贝 5 深拷贝 参考文献 1 变量与对象 对象:内存中存储数据的实体,有明确的类型.在Py ...
- python 深拷贝_详解python的复制,深拷贝和浅拷贝的区别
概述 今天主要来看看Python中的浅拷贝和深拷贝内容,这里用一个实例来说明~ 需求: 将一个列表的数据复制到另一个列表中. 思路: 使用列表[:],拿不准可以调用copy模块. 实现方法: #!/u ...
- c++深拷贝和浅拷贝的区别?
c++深拷贝和浅拷贝的区别 浅拷贝 深拷贝 总结 浅拷贝 对一个已知对象进行拷贝,编译系统会自动调用一种构造函数--拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数,调用一次构造函数 ...
- Python中深拷贝与浅拷贝的区别?
往期面试题: 列举Python中的标准异常类? 说说Python面向对象三大特性? 说说Python中有几种数据类型? 说说Python模块主要分哪三类? 废话不多说,开始今天的题目: 问:说说Pyt ...
- 深拷贝与浅拷贝的区别
深浅拷贝的区别: 浅拷贝是将原始对象中的数据型字段拷贝到新对象中去,将引用型字段的"引用"复制到新对象中去,不把"引用的对象"复制进去,所以原始对象和新 ...
- 【233】python—深拷贝与浅拷贝的区别
♣ 题目部分(原文见公众号:python宝) python宝 https://mp.weixin.qq.com/mp/profile_ext?action=home&__biz=MzU5NjI ...
最新文章
- 麻省理工学院的牛人解说数学体系,你到哪个层次了?
- HDU 1004 Let the Balloon Rise
- 机器学习十大算法(二)
- .c/.cpp文件形成.exe文件的过程
- react入门--------安装react
- 什么浏览器好用_手机浏览器不只UC,好用的浏览器还有这些
- 计算机研究与发展 杂志,《计算机研究与发展》杂志投稿的具体要求详解
- (58)UART外设驱动用户发送模块(三)(第12天)
- 【Java数据结构与算法】第二章 单链表及简单面试题
- linux centos java 应用服务器配置
- 从底层分析python中深拷贝和浅拷贝区别
- 模板方法模式-Template Method Pattern
- echarts三维建筑地图注解
- 用一行`CSS`实现10种布局
- 九月新版【自动赚钱广告机广告阅读收入】新版金多多广告机源代码看广告看新闻赚钱自动钱广告机源代码自动广告阅读收入
- 向量场的散度和旋度_矢量场,标量场,散度,梯度,旋度的理解
- ARM惹众怒,美国芯片行业也开始抛弃它,跟随中国芯片支持新架构
- Maven使用(1)
- GB28181协议常见几种信令流程(二)
- Unity中空气墙的制作
热门文章
- 高精度ADC采集电量显示(MCP3421)
- linux编译trinitycore,在Ubuntu上搭建基于TrinityCore的魔兽私服
- Excel中函数Vlookup的应用
- 怎样的人适合当码农?
- 比较RoamResearch,Obsidian,Remnote
- Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离详解【转载】
- 电脑开机黑屏不显示任何东西 电脑黑屏什么都不显示怎么回事
- redis主从复制,复制功能是高可用Redis的基础,为满足故障恢复和负载均衡等需求把Redis数据复制多个副本部署到其他机器;如何实现redis的主从复制模式以及主从复制模式下常见的运维问题;
- plsa java_PLSA算法(转)
- 描述对未来计算机的畅想用英语作文,对未来计算机的畅想英语作文 关于对未来计算机的畅想的英语作文...