基础面试题:深拷贝和浅拷贝详解以及实例
深拷贝 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不再是梦想!
基础面试题:深拷贝和浅拷贝详解以及实例相关推荐
- python深拷贝一个对象_Python对象的深拷贝和浅拷贝详解
本文内容是在<Python核心编程2>上看到的,感觉很有用便写出来,给大家参考参考! 浅拷贝 首先我们使用两种方式来拷贝对象,一种是切片,另外一种是工厂方法.然后使用id函数来看看它们的标 ...
- c++拷贝构造函数(深拷贝,浅拷贝)详解
一.什么是拷贝构造函数 首先对于普通类型的对象来说,它们之间的复制是很简单的,例如: int a=100; int b=a; 而类对象与普通对象不同,类对象内部结构一般较为复杂,存在各种成 ...
- iOS开发——深拷贝与浅拷贝详解
深拷贝和浅拷贝这个问题在面试中常常被问到,而在实际开发中,只要稍有不慎,就会在这里出现问题.尤其对于初学者来说,我们有必要来好好研究下这个概念.我会以实际代码来演示,相关示例代码上传至 这里 . 首先 ...
- 【Java深入】深拷贝与浅拷贝详解
1.拷贝的引入 (1)引用拷贝 创建一个指向对象的引用变量的拷贝. 例1: Teacher teacher = new Teacher("Taylor",26); Teacher ...
- python深复制与浅复制_Python中的深拷贝和浅拷贝详解
要说清楚Python中的深浅拷贝,需要搞清楚下面一系列概念: 变量-引用-对象(可变对象,不可变对象)-切片-拷贝(浅拷贝,深拷贝) [变量-对象-引用] 在Python中一切都是对象,比如说:3, ...
- python中深拷贝和浅拷贝_**Python中的深拷贝和浅拷贝详解
甚至连type其本身都是对象,type对象 Python中变量与C/C++/Java中不同,它是指对象的引用,Python是动态类型,程序运行时候,会根据对象的类型 来确认变量到底是什么类型. 单独赋 ...
- 【Linux基础】 diff命令的参数详解和实例
diff命令参数: diff - 找出两个文件的不同点 总览 diff [选项] 源文件 目标文件 描述 在最简单的情况是, diff 比较两个文件的内容 (源文件 和 目标文件). 文件名可以是 - ...
- js 浅拷贝直接赋值_JS中实现浅拷贝和深拷贝的代码详解
(一)JS中基本类型和引用类型 JavaScript的变量中包含两种类型的值:基本类型值 和 引用类型值,在内存中的表现形式在于:前者是存储在栈中的一些简单的数据段,后者则是保存在堆内存中的一个对象. ...
- python复制列表元素_Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解...
Python学习教程:Python列表赋值,复制,深拷贝及5种浅拷贝详解 概述 在列表复制这个问题,看似简单的复制却有着许多的学问,尤其是对新手来说,理所当然的事情却并不如意,比如列表的赋值.复制.浅 ...
最新文章
- 当前最佳的YOLOv4是如何炼成的?细数那些小细节
- numpy使用[]语法索引二维numpy数组中指定指定行之前所有数据行的数值内容(accessing rows in numpy array before specifc row)
- Cordova入门系列(一)创建项目
- python (ploit3)hexun
- Master Data Service调用API创建Model
- 关于EGE图形库在CodeBlocks下的配置
- Kafka设计解析(五): Kafka Consumer设计解析
- 北大清华人大中关村周围二手书店淘书全攻略
- TongWeb和Tomcat的区别
- 二级c语言考试怎么调试程序,计算机二级C语言上机考试操作步骤及流程和注意事项...
- Keil5下载芯片包并导入教程
- 如何将Excel表格随机打乱顺序
- 【Java】爬虫,看完还爬不下来打我电话
- 连续分配存储管理,覆盖交换和存储碎片
- spring gateway route超时时间原理解析和gateway调用流程
- 如何快速的将word文档中的图片提取出来
- vue3 简单封装GoogleMap组件
- 解决桌面图标无法拖动之绝招
- 交换机端口隔离port-isolate
- STM32f1之简单控制继电器模块(附源码)
热门文章
- CHY Web 3 Move
- 【Unity3D】流动雾效
- moco接口框架介绍
- nRF52832 Power
- 使用pytorch进行风格迁移,以艺术绘画的风格来生成一些好玩的图片
- JS数组对象,过滤掉不要的对象
- Spring5学习笔记二
- 项目自动打包部署脚本
- java setproperty作用_Java中System.setProperty()用法
- Ubuntu开机卡在 A start job is runing for wait for Network to be configured (1min 23s / no limit)解决方法