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

深拷贝与浅拷贝的问题,也是面试中的常客 。虽然大家都知道两者表现形式不同点在哪里,但是很少去深究其底层原理,也不知道怎么才能优雅的实现一个深拷贝 。其实工作中也常常需要实现深拷贝,今天一灯就带大家一块深入剖析一下深拷贝与浅拷贝的实现原理,并手把手教你怎么优雅的实现深拷贝 。
1. 什么是深拷贝与浅拷贝浅拷贝: 只拷贝栈内存中的数据,不拷贝堆内存中数据 。
深拷贝: 既拷贝栈内存中的数据,又拷贝堆内存中的数据 。
2. 浅拷贝的实现原理由于浅拷贝只拷贝了栈内存中数据,栈内存中存储的都是基本数据类型,堆内存中存储了数组、引用数据类型等 。

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

文章插图
使用代码验证一下:
想要实现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":"一灯架构","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. 深拷贝的实现原理深拷贝是既拷贝栈内存中的数据,又拷贝堆内存中的数据 。
死磕Java面试系列:深拷贝与浅拷贝的实现原理

文章插图
实现深拷贝有很多种方法,下面就详细讲解一下,看使用哪种方式更方便快捷 。
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":"一灯架构","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);}}

推荐阅读