文章目录

  • 前言
  • 1. 什么是深拷贝与浅拷贝
  • 2. 浅拷贝的实现原理
  • 3. 深拷贝的实现原理
    • 3.1 实现Cloneable接口
    • 3.2 使用JSON字符串转换
    • 3.3 集合实现深拷贝
  • 总结

前言

深拷贝与浅拷贝的问题,也是面试中的常客。虽然大家都知道两者表现形式不同点在哪里,但是很少去深究其底层原理,也不知道怎么才能优雅的实现一个深拷贝。

其实工作中也常常需要实现深拷贝,今天就带大家一块深入剖析一下深拷贝与浅拷贝的实现原理,并手把手教你怎么优雅的实现深拷贝。

1. 什么是深拷贝与浅拷贝

浅拷贝: 只拷贝栈内存中的数据,不拷贝堆内存中数据。
深拷贝: 既拷贝栈内存中的数据,又拷贝堆内存中的数据。

2. 浅拷贝的实现原理

由于浅拷贝只拷贝了栈内存中数据,栈内存中存储的都是基本数据类型,堆内存中存储了数组、引用数据类型等。

使用代码验证一下:
想要实现clone功能,需要实现 Cloneable 接口,并重写 clone 方法。

  1. 先创建一个用户类

// 用户的实体类,用作验证

public class User implements Cloneable {private String name;// 每个用户都有一个工作private Job job;public String getName() {return name;}public void setName(String name) {this.name = name;}public Job getJob() {return job;}public void setJob(Job job) {this.job = job;}@Overridepublic User clone() throws CloneNotSupportedException {User user = (User) super.clone();return user;}
}
  1. 再创建一个工作类
// 工作的实体类,并没有实现Cloneable接口
public class Job {private String content;public String getContent() {return content;}public void setContent(String content) {this.content = content;}
}
  1. 测试浅拷贝
/*** @author * @apiNote Java浅拷贝示例**/
public class Demo {public static void main(String[] args) throws CloneNotSupportedException {// 1. 创建用户对象,{"name":"demo","job":{"content":"开发"}}User user1 = new User();user1.setName("demo");Job job1 = new Job();job1.setContent("开发");user1.setJob(job1);// 2. 拷贝用户对象,name修改为"张三",工作内容修改"测试"User user2 = user1.clone();user2.setName("张三");Job job2 = user2.getJob();job2.setContent("测试");// 3. 输出结果System.out.println("user原对象= " + user1);System.out.println("user拷贝对象= " + user2);}}

输出结果:

user原对象= {"name":"demo","job":{"content":"测试"}}
user拷贝对象= {"name":"张三","job":{"content":"测试"}}

从结果中可以看出,对象拷贝把name修改为”张三“,原对象并没有变,name是String类型,是基本数据类型,存储在栈内存中。对象拷贝了一份新的栈内存数据,修改并不会影响原对象。

然后对象拷贝把Job中content修改为”测试“,原对象也跟着变了,原因是Job是引用类型,存储在堆内存中。对象拷贝和原对象指向的同一个堆内存的地址,所以修改会影响到原对象。

3. 深拷贝的实现原理

深拷贝是既拷贝栈内存中的数据,又拷贝堆内存中的数据。

实现深拷贝有很多种方法,下面就详细讲解一下,看使用哪种方式更方便快捷。

3.1 实现Cloneable接口

通过实现Cloneable接口来实现深拷贝是最常见的。

想要实现clone功能,需要实现Cloneable接口,并重写clone方法。

  1. 先创建一个用户类
// 用户的实体类,用作验证
public class User implements Cloneable {private String name;// 每个用户都有一个工作private Job job;public String getName() {return name;}public void setName(String name) {this.name = name;}public Job getJob() {return job;}public void setJob(Job job) {this.job = job;}@Overridepublic User clone() throws CloneNotSupportedException {User user = (User) super.clone();// User对象中所有引用类型属性都要执行clone方法user.setJob(user.getJob().clone());return user;}
}
  1. 再创建一个工作类
// 工作的实体类,需要实现Cloneable接口
public class Job implements Cloneable {private String content;public String getContent() {return content;}public void setContent(String content) {this.content = content;}@Overrideprotected Job clone() throws CloneNotSupportedException {return (Job) super.clone();}
}
  1. 测试浅拷贝
/*** @author * @apiNote Java深拷贝示例**/
public class Demo {public static void main(String[] args) throws CloneNotSupportedException {// 1. 创建用户对象,{"name":"demo","job":{"content":"开发"}}User user1 = new User();user1.setName("demo");Job job1 = new Job();job1.setContent("开发");user1.setJob(job1);// 2. 拷贝用户对象,name修改为"张三",工作内容修改"测试"User user2 = user1.clone();user2.setName("张三");Job job2 = user2.getJob();job2.setContent("测试");// 3. 输出结果System.out.println("user原对象= " + user1);System.out.println("user拷贝对象= " + user2);}}

输出结果:

user原对象= {"name":"demo","job":{"content":"开发"}}
user拷贝对象= {"name":"张三","job":{"content":"测试"}}

从结果中可以看出,user拷贝对象修改了name属性和Job对象中内容,都没有影响到原对象,实现了深拷贝。

通过实现Cloneable接口的方式来实现深拷贝,是Java中最常见的实现方式。

缺点是: 比较麻烦,需要所有实体类都实现Cloneable接口,并重写clone方法。如果实体类中新增了一个引用对象类型的属性,还需要添加到clone方法中。如果继任者忘了修改clone方法,相当于挖了一个坑。

3.2 使用JSON字符串转换

实现方式就是:

  1. 先把user对象转换成json字符串
  2. 再把json字符串转换成user对象

这是个偏方,但是偏方治大病,使用起来非常方便,一行代码即可实现。
下面使用fastjson实现,使用Gson、Jackson也是一样的:

import com.alibaba.fastjson.JSON;/*** @author * @apiNote Java深拷贝示例**/
public class Demo {public static void main(String[] args) throws CloneNotSupportedException {// 1. 创建用户对象,{"name":"demo","job":{"content":"开发"}}User user1 = new User();user1.setName("demo");Job job1 = new Job();job1.setContent("开发");user1.setJob(job1); 2. 拷贝用户对象,name修改为"张三",工作内容修改"测试"User user2 = JSON.parseObject(JSON.toJSONString(user1), User.class);user2.setName("张三");Job job2 = user2.getJob();job2.setContent("测试");// 3. 输出结果System.out.println("user原对象= " + JSON.toJSONString(user1));System.out.println("user拷贝对象= " + JSON.toJSONString(user2));}}

输出结果:

user原对象= {"name":"demo","job":{"content":"开发"}}
user拷贝对象= {"name":"张三","job":{"content":"测试"}}

从结果中可以看出,user拷贝对象修改了name属性和Job对象中内容,并没有影响到原对象,实现了深拷贝。

3.3 集合实现深拷贝

再说一下Java集合怎么实现深拷贝?

其实非常简单,只需要初始化新对象的时候,把原对象传入到新对象的构造方法中即可。

以最常用的ArrayList为例:

/*** @author * @apiNote Java深拷贝示例**/
public class Demo {public static void main(String[] args) throws CloneNotSupportedException {// 1. 创建原对象List<User> userList = new ArrayList<>();// 2. 创建深拷贝对象List<User> userCopyList = new ArrayList<>(userList);}}

总结

本文介绍了什么是浅拷贝和深拷贝,以及其实现原理希望对你有帮助,欢迎评论区互动留言。

【面试】深拷贝与浅拷贝的实现原理相关推荐

  1. foreach的工作原理和深拷贝、浅拷贝

    一.foreach的工作原理 二.拷贝.深拷贝和浅拷贝 转载于:https://www.cnblogs.com/wesley168/p/6814418.html

  2. 面试篇---1 如何区分深拷贝与浅拷贝

    如何区分深拷贝与浅拷贝? 简单来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力. 浅拷贝例子: var a=[0 ...

  3. “约见”面试官系列之常见面试题第十八篇之深拷贝和浅拷贝得区别(建议收藏)

     壹 ❀ 引 如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力. 此篇文章中也会简 ...

  4. 面试官:谈谈你对深拷贝和浅拷贝的理解

    在面试的时候,如果面试官问对你说:请谈谈你对深拷贝和浅拷贝的理解,你会怎么回答这个问题呢?可能有很多小伙伴都不太理解深拷贝和浅拷贝的含义和区别,那么今天就和各位小伙伴分享一下我对二者的理解

  5. 【C++面试问答】搞清楚深拷贝与浅拷贝的区别

    问题 深拷贝和浅拷贝的区别是面试中的常见问题之一,对于不同的编程语言,这个问题的回答可能稍有差别,下面我们就来探索一下它们之间的异同吧. 先来看看在JavaScript对象的深拷贝与浅拷贝的区别: 浅 ...

  6. 如何完美解答面试问题——深拷贝和浅拷贝的区别

    大家好,我是孤焰.今天要谈一谈在面试过程中可能被面试官提到的一个问题--深拷贝和浅拷贝的区别? 由于我也是刚刚学习编程的小白,所以此篇博文将参考了多篇博文,最后总结而成. 最近由于多门考试临近,所以博 ...

  7. 深拷贝和浅拷贝的区别和与原理

    一.基本类型和引用类型 string,number,boolean,null,undefined,symbol Function,Array,Object 基本类型是按值访问的,引用类型是按引用访问 ...

  8. Python 精选笔试面试习题—类继承、方法对象、包管理、闭包、可变类型作为默认参数、列表引用、sort与sorted、 append 和 extend、深拷贝和浅拷贝

    1. 类继承 如下代码 class A(object):def show(self):print 'This is calss A'class B(A):def show(self):print 'T ...

  9. 深入浅出解释深拷贝、浅拷贝、对象拷贝、引用拷贝原理和应用

    拷贝总体上分为引用拷贝和对象拷贝. 1. 引用拷贝 创建一个指向对象的引用变量的拷贝. public class QuoteCopy {public static void main(String[] ...

最新文章

  1. 登顶Nature | DeepMind用AI首次实现数学领域重大进展,助力科学家证实两大猜想
  2. 功率增长步长(powerRampingStep)
  3. 浏览器上网 (Safari Chrome)
  4. 手把手教你如何安装多个node版本
  5. python多线程编程(5): 条件变量同步
  6. 【C++】For循环同时初始化两个变量
  7. 3.1 SE11创建域
  8. 相量除法能用计算机吗,电路相量的加减乘除运算
  9. mybatis如何查询主键
  10. C语言学习笔记---结构体中的字符数组和字符指针
  11. 如何使用vue使同一个弹窗同时能实现添加和编辑
  12. python 变量命名空间_Python命名空间– Python变量范围
  13. windbg学习---?? 和 ?
  14. 通讯简单测试—Modscan32使用简介-Susie 周
  15. 基于STM32CUBE MX 的TM1640的使用例程
  16. Unity AI 之 行为树 的简单介绍
  17. win10在哪打开ie浏览器?windows11怎么打开ie浏览器?
  18. Leaflet制作专题图
  19. Android api level对照表
  20. MATLAB快速读取STL文件

热门文章

  1. 审计数据在EntityFramework中的解决方案
  2. 分类4:机器学习处理乳腺癌数据集代码
  3. 福布斯2014中国最具潜力中小企业榜出炉
  4. Java实现美团验劵功能
  5. Ez-USB FX3的GPIF II接口
  6. 微信小程序壁纸源码+自动采集小米图片
  7. 【漏洞复现】Apache Shiro 反序列化漏洞
  8. vue基础学习记录(一)
  9. yum/dnf 安装mariadb10.4.8(最新版)
  10. python如何播放视频_在网上看到一个视频!怎么下载下来啊?