深拷贝 vs 浅拷贝

浅拷贝

概念

复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针,不复制堆内存中的对象。

如图:

特点

​ 1.对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个。
2.对于引用类型,比如数组或者类对象,因为引用类型是引用传递,所以浅拷贝只是把内存地址赋值给了成员变量,它们指向了同一内存空间。改变其中一个,会对另外一个也产生影响。

实现

​ 实现 Cloneable 接口,重写 clone() 方法

/*** @ClassName ShallowCopyDemo* @Description: 实现 Cloneable 接口,重写 clone() 方法。* @Author fking* @Date 2020/4/30 0030* @Version V1.0**/
public class ShallowCopyDemo {public static void main(String[] args) throws CloneNotSupportedException {Person p1 = new Person(1, "fking01");//创建对象 Person p1Person p2 = (Person)p1.clone();//克隆对象 p1p2.setName("fking02");//修改 p2的name属性,p1的name未变System.out.println(p1);System.out.println(p2);p2 = p1;p2.setName("fking02");//修改 p2的name属性,p1的也跟着变System.out.println(p1);System.out.println(p2);}
}class Person implements Cloneable {private int pid;private String name;public Person(int pid, String name) {this.pid = pid;this.name = name;System.out.println("Person constructor call");}public int getPid() {return pid;}public void setPid(int pid) {this.pid = pid;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}@Overridepublic String toString() {return "Person [pid:" + pid + ", name:" + name + "]";}
}

深拷贝

概念

​ 复制基本类型的属性;引用类型的属性复制,复制栈中的变量 和 变量指向堆内存中的对象的指针和堆内存中的对象。

特点

​ 1.对于基本数据类型的成员对象,因为基础数据类型是值传递的,所以是直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个(和浅拷贝一样)。

​ 2.对于引用类型,比如数组或者类对象,深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间。改变其中一个,不会对另外一个也产生影响。

​ 3.对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝。

​ 4.深拷贝相比于浅拷贝速度较慢并且花销较大。

实现方式

​ 1.对象的属性的Class 也实现 Cloneable 接口,在克隆对象时也手动克隆属性

/*** @ClassName DeepCopyDemo01* @Description: 对象的属性的Class 也实现 Cloneable 接口,在克隆对象时也手动克隆属性。* @Author fking* @Date 2020/4/30 0030* @Version V1.0**/
public class DeepCopyDemo01 {public static void main(String[] args) throws CloneNotSupportedException {DPerson01 p1 = new DPerson01(1, "fking01", new DFood01("food01"));//创建Person 对象 p1DPerson01 p2 = (DPerson01)p1.clone();//克隆p1p2.setName("fking02");//修改p2的name属性p2.getFood().setName("food02");//修改p2的自定义引用类型 food 属性System.out.println(p1);//修改p2的自定义引用类型 food 属性被改变,p1的自定义引用类型 food 属性也随之改变,说明p2的food属性,只拷贝了引用,没有拷贝food对象System.out.println(p2);}
}class DPerson01 implements Cloneable {private int pid;private String name;private DFood01 food;public DPerson01(int pid, String name, DFood01 food) {this.pid = pid;this.name = name;this.food = food;System.out.println("DPerson01 constructor call");}public int getPid() {return pid;}public void setPid(int pid) {this.pid = pid;}public String getName() {return name;}public void setName(String name) {this.name = name;}/*** 对象的属性的Class 也实现 Cloneable 接口,在克隆对象时也手动克隆属性。* @return* @throws CloneNotSupportedException*/@Overridepublic Object clone() throws CloneNotSupportedException {DPerson01 p = (DPerson01)super.clone();p.setFood((DFood01)p.getFood().clone());return p;}@Overridepublic String toString() {return "DPerson01 [pid:"+pid+", name:"+name+", food:"+food.getName()+"]";}public DFood01 getFood() {return food;}public void setFood(DFood01 food) {this.food = food;}}class DFood01 implements Cloneable {private String name;public DFood01(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}
}

​ 2.结合序列化(JDK java.io.Serializable 接口、JSON格式、XML格式等),完成深拷贝

/*** @ClassName DeepCopyDemo02* @Description: 结合序列化(JDK java.io.Serializable 接口、JSON格式、XML格式等),完成深拷贝* @Author fking* @Date 2020/4/30 0030* @Version V1.0**/
public class DeepCopyDemo02 {public static void main(String[] args) throws CloneNotSupportedException {DPerson02 p1 = new DPerson02(1, "fking01", new SFood02("food01"));//创建 DPerson02 对象 p1DPerson02 p2 = (DPerson02)p1.cloneBySerializable();//克隆 p1p2.setName("fking02");//修改 p2 的 name 属性p2.getFood().setName("food02");//修改 p2 的自定义引用类型 food 属性System.out.println(p1);//修改 p2 的自定义引用类型 food 属性被改变,p1的自定义引用类型 food 属性未随之改变,说明p2的food属性,只拷贝了引用和 food 对象System.out.println(p2);}
}class DPerson02 implements Cloneable, Serializable {private static final long serialVersionUID = -7710144514831611031L;private int pid;private String name;private SFood02 food;public DPerson02(int pid, String name, SFood02 food) {this.pid = pid;this.name = name;this.food = food;System.out.println("DPerson02 constructor call");}public int getPid() {return pid;}public void setPid(int pid) {this.pid = pid;}public String getName() {return name;}public void setName(String name) {this.name = name;}/*** 通过序列化完成克隆* @return*/public Object cloneBySerializable() {Object obj = null;try {ByteArrayOutputStream baos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(baos);oos.writeObject(this);ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bais);obj = ois.readObject();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}return obj;}@Overridepublic String toString() {return "DPerson02 [pid:"+pid+", name:"+name+", food:"+food.getName()+"]";}public SFood02 getFood() {return food;}public void setFood(SFood02 food) {this.food = food;}}class SFood02 implements Serializable {private static final long serialVersionUID = -3443815804346831432L;private String name;public SFood02(String name) {this.name = name;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

如果大家对java架构相关感兴趣,可以关注下面公众号,会持续更新java基础面试题, netty, spring boot,spring cloud等系列文章,一系列干货随时送达, 超神之路从此展开, BTAJ不再是梦想!

基础面试题:深拷贝和浅拷贝详解以及实例相关推荐

  1. python深拷贝一个对象_Python对象的深拷贝和浅拷贝详解

    本文内容是在<Python核心编程2>上看到的,感觉很有用便写出来,给大家参考参考! 浅拷贝 首先我们使用两种方式来拷贝对象,一种是切片,另外一种是工厂方法.然后使用id函数来看看它们的标 ...

  2. c++拷贝构造函数(深拷贝,浅拷贝)详解

    一.什么是拷贝构造函数       首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=100; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成 ...

  3. iOS开发——深拷贝与浅拷贝详解

    深拷贝和浅拷贝这个问题在面试中常常被问到,而在实际开发中,只要稍有不慎,就会在这里出现问题.尤其对于初学者来说,我们有必要来好好研究下这个概念.我会以实际代码来演示,相关示例代码上传至 这里 . 首先 ...

  4. 【Java深入】深拷贝与浅拷贝详解

    1.拷贝的引入 (1)引用拷贝 创建一个指向对象的引用变量的拷贝. 例1: Teacher teacher = new Teacher("Taylor",26); Teacher ...

  5. python深复制与浅复制_Python中的深拷贝和浅拷贝详解

    要说清楚Python中的深浅拷贝,需要搞清楚下面一系列概念: 变量-引用-对象(可变对象,不可变对象)-切片-拷贝(浅拷贝,深拷贝) [变量-对象-引用] 在Python中一切都是对象,比如说:3, ...

  6. python中深拷贝和浅拷贝_**Python中的深拷贝和浅拷贝详解

    甚至连type其本身都是对象,type对象 Python中变量与C/C++/Java中不同,它是指对象的引用,Python是动态类型,程序运行时候,会根据对象的类型 来确认变量到底是什么类型. 单独赋 ...

  7. 【Linux基础】 diff命令的参数详解和实例

    diff命令参数: diff - 找出两个文件的不同点 总览 diff [选项] 源文件 目标文件 描述 在最简单的情况是, diff 比较两个文件的内容 (源文件 和 目标文件). 文件名可以是 - ...

  8. js 浅拷贝直接赋值_JS中实现浅拷贝和深拷贝的代码详解

    (一)JS中基本类型和引用类型 JavaScript的变量中包含两种类型的值:基本类型值 和 引用类型值,在内存中的表现形式在于:前者是存储在栈中的一些简单的数据段,后者则是保存在堆内存中的一个对象. ...

  9. python复制列表元素_Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解...

    Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解 概述 在列表复制这个问题,看似简单的复制却有着许多的学问,尤其是对新手来说,理所当然的事情却并不如意,比如列表的赋值.复制.浅 ...

最新文章

  1. 当前最佳的YOLOv4是如何炼成的?细数那些小细节
  2. numpy使用[]语法索引二维numpy数组中指定指定行之前所有数据行的数值内容(accessing rows in numpy array before specifc row)
  3. Cordova入门系列(一)创建项目
  4. python (ploit3)hexun
  5. Master Data Service调用API创建Model
  6. 关于EGE图形库在CodeBlocks下的配置
  7. Kafka设计解析(五): Kafka Consumer设计解析
  8. 北大清华人大中关村周围二手书店淘书全攻略
  9. TongWeb和Tomcat的区别
  10. 二级c语言考试怎么调试程序,计算机二级C语言上机考试操作步骤及流程和注意事项...
  11. Keil5下载芯片包并导入教程
  12. 如何将Excel表格随机打乱顺序
  13. 【Java】爬虫,看完还爬不下来打我电话
  14. 连续分配存储管理,覆盖交换和存储碎片
  15. spring gateway route超时时间原理解析和gateway调用流程
  16. 如何快速的将word文档中的图片提取出来
  17. vue3 简单封装GoogleMap组件
  18. 解决桌面图标无法拖动之绝招
  19. 交换机端口隔离port-isolate
  20. STM32f1之简单控制继电器模块(附源码)

热门文章

  1. CHY Web 3 Move
  2. 【Unity3D】流动雾效
  3. moco接口框架介绍
  4. nRF52832 Power
  5. 使用pytorch进行风格迁移,以艺术绘画的风格来生成一些好玩的图片
  6. JS数组对象,过滤掉不要的对象
  7. Spring5学习笔记二
  8. 项目自动打包部署脚本
  9. java setproperty作用_Java中System.setProperty()用法
  10. Ubuntu开机卡在 A start job is runing for wait for Network to be configured (1min 23s / no limit)解决方法