死磕Java面试系列:深拷贝与浅拷贝的实现原理(深拷贝和浅拷贝实现)

  本篇文章为你整理了死磕Java面试系列:深拷贝与浅拷贝的实现原理(深拷贝和浅拷贝实现)的详细内容,包含有深拷贝 浅拷贝 java 深拷贝和浅拷贝实现 深拷贝和浅拷贝实现方式 深拷贝和浅拷贝使用场景 死磕Java面试系列:深拷贝与浅拷贝的实现原理,希望能帮助你了解 死磕Java面试系列:深拷贝与浅拷贝的实现原理。

   深拷贝与浅拷贝的问题,也是面试中的常客。虽然大家都知道两者表现形式不同点在哪里,但是很少去深究其底层原理,也不知道怎么才能优雅的实现一个深拷贝。其实工作中也常常需要实现深拷贝,今天一灯就带大家一块深入剖析一下深拷贝与浅拷贝的实现原理,并手把手教你怎么优雅的实现深拷贝。

  
深拷贝与浅拷贝的问题,也是面试中的常客。虽然大家都知道两者表现形式不同点在哪里,但是很少去深究其底层原理,也不知道怎么才能优雅的实现一个深拷贝。其实工作中也常常需要实现深拷贝,今天一灯就带大家一块深入剖析一下深拷贝与浅拷贝的实现原理,并手把手教你怎么优雅的实现深拷贝。

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

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

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

  2. 浅拷贝的实现原理

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

  使用代码验证一下:

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

  先创建一个用户类

  

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

 

  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;

  
public User clone() throws CloneNotSupportedException {

   User user = (User) super.clone();

   return user;

  

 

  再创建一个工作类

  

// 工作的实体类,并没有实现Cloneable接口

 

  public class Job {

   private String content;

   public String getContent() {

   return content;

   public void setContent(String content) {

   this.content = content;

  

 

  测试浅拷贝

  

/**

 

   * @author 一灯架构

   * @apiNote Java浅拷贝示例

  public class Demo {

   public static void main(String[] args) throws CloneNotSupportedException {

   // 1. 创建用户对象,{"name":"一灯架构","job":{"content":"开发"}}

   User user1 = new User();

   user1.setName("一灯架构");

   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":"一灯架构","job":{"content":"测试"}}

 

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

  

 

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

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

  3. 深拷贝的实现原理

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

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

  3.1 实现Cloneable接口

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

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

  先创建一个用户类

  

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

 

  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;

  
public User clone() throws CloneNotSupportedException {

   User user = (User) super.clone();

   // User对象中所有引用类型属性都要执行clone方法

   user.setJob(user.getJob().clone());

   return user;

  

 

  再创建一个工作类

  

// 工作的实体类,需要实现Cloneable接口

 

  public class Job implements Cloneable {

   private String content;

   public String getContent() {

   return content;

   public void setContent(String content) {

   this.content = content;

   @Override

   protected Job clone() throws CloneNotSupportedException {

   return (Job) super.clone();

  

 

  测试浅拷贝

  

/**

 

   * @author 一灯架构

   * @apiNote Java深拷贝示例

  public class Demo {

   public static void main(String[] args) throws CloneNotSupportedException {

   // 1. 创建用户对象,{"name":"一灯架构","job":{"content":"开发"}}

   User user1 = new User();

   user1.setName("一灯架构");

   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":"一灯架构","job":{"content":"开发"}}

 

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

  

 

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

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

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

  3.2 使用JSON字符串转换

  实现方式就是:

  先把user对象转换成json字符串

  再把json字符串转换成user对象

  这是个偏方,但是偏方治大病,使用起来非常方便,一行代码即可实现。

  下面使用fastjson实现,使用Gson、Jackson也是一样的:

  

import com.alibaba.fastjson.JSON;

 

  
public static void main(String[] args) throws CloneNotSupportedException {

   // 1. 创建用户对象,{"name":"一灯架构","job":{"content":"开发"}}

   User user1 = new User();

   user1.setName("一灯架构");

   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":"一灯架构","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);

  

 

  我是「一灯架构」,如果本文对你有帮助,欢迎各位小伙伴点赞、评论和关注,感谢各位老铁,我们下期见

  以上就是死磕Java面试系列:深拷贝与浅拷贝的实现原理(深拷贝和浅拷贝实现)的详细内容,想要了解更多 死磕Java面试系列:深拷贝与浅拷贝的实现原理的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: