java数组深拷贝和浅拷贝_java中的深拷贝与浅拷贝(值类型 vs 引用类型)

对象赋值

赋值是日常编程过程中最常见的操作,最简单的比如:

Student codeSheep = new Student(); Student codePig = codeSheep;

严格来说,这种不能算是对象拷贝,因为拷贝的仅仅只是引用关系,并没有生成新的实际对象:

47883fc65f165f6244e03f62cf7ca555.png

浅拷贝

浅拷贝属于对象克隆方式的一种,重要的特性体现在这个 「浅」 字上。

比如我们试图通过studen1实例,拷贝得到student2,如果是浅拷贝这种方式,大致模型可以示意成如下所示的样子:

3113480260b1a89db144439bab058364.png

很明显,值类型的字段会复制一份,而引用类型的字段拷贝的仅仅是引用地址,而该引用地址指向的实际对象空间其实只有一份。

深拷贝

深拷贝相较于上面所示的浅拷贝,除了值类型字段会复制一份,引用类型字段所指向的对象,会在内存中也创建一个副本

4bcb1e54030a69c84b3546162cfb4d41.png

浅拷贝代码实现

还以上文的例子来讲,我想通过student1拷贝得到student2,浅拷贝的典型实现方式是:让被复制对象的类实现Cloneable接口,并重写clone()方法即可。

以上面的Student类拷贝为例:

public class Student implements Cloneable { private String name; // 姓名 private int age; // 年龄 private Major major; // 所学专业 @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } // ... 其他省略 ... }

public class Test { public static void main(String[] args) throws CloneNotSupportedException { Major m = new Major("计算机科学与技术",666666); Student student1 = new Student( "CodeSheep", 18, m ); // 由 student1 拷贝得到 student2 Student student2 = (Student) student1.clone(); System.out.println( student1 == student2 ); System.out.println( student1 ); System.out.println( student2 ); System.out.println( "\n" ); // 修改student1的值类型字段 student1.setAge( 35 ); // 修改student1的引用类型字段 m.setMajorName( "电子信息工程" ); m.setMajorId( 888888 ); System.out.println( student1 ); System.out.println( student2 ); } }

运行结果:

7259725d3595374897198628f479f489.png

从结果可以看出:

student1==student2打印false,说明clone()方法的确克隆出了一个新对象;

修改值类型字段并不影响克隆出来的新对象,符合预期;

而修改了student1内部的引用对象,克隆对象student2也受到了波及,说明内部还是关联在一起的

深拷贝代码实现

深度遍历式拷贝

虽然clone()方法可以完成对象的拷贝工作,但是注意:clone()方法默认是浅拷贝行为,就像上面的例子一样。若想实现深拷贝需覆写 clone()方法实现引用对象的深度遍历式拷贝,进行地毯式搜索。

所以对于上面的例子,如果想实现深拷贝,首先需要对更深一层次的引用类Major做改造,让其也实现Cloneable接口并重写clone()方法:

public class Major implements Cloneable { @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } // ... 其他省略 ... }

其次我们还需要在顶层的调用类中重写clone方法,来调用引用类型字段的clone()方法实现深度拷贝,对应到本文那就是Student类:

public class Student implements Cloneable { @Override public Object clone() throws CloneNotSupportedException { Student student = (Student) super.clone(); student.major = (Major) major.clone(); // 重要!!! return student; } // ... 其他省略 ... }

这时候上面的测试用例不变,运行可得结果:

10ab389d5758108f65f4deaef089507a.png

391e023c9082fe6326f11da13b87d4ff.png

很明显,这时候student1和student2两个对象就完全独立了,不受互相的干扰。

利用反序列化实现深拷贝

利用反序列化技术,我们也可以从一个对象深拷贝出另一个复制对象,而且在解决多层套娃式的深拷贝问题时效果出奇的好。

所以我们这里改造一下Student类,让其clone()方法通过序列化和反序列化的方式来生成一个原对象的深拷贝副本:

public class Student implements Serializable { private String name; // 姓名 private int age; // 年龄 private Major major; // 所学专业 public Student clone() { try { // 将对象本身序列化到字节流 ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream( byteArrayOutputStream ); objectOutputStream.writeObject( this ); // 再将字节流通过反序列化方式得到对象副本 ObjectInputStream objectInputStream = new ObjectInputStream( new ByteArrayInputStream( byteArrayOutputStream.toByteArray() ) ); return (Student) objectInputStream.readObject(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } // ... 其他省略 ... }

当然这种情况下要求被引用的子类(比如这里的Major类)也必须是可以序列化的,即实现了Serializable接口:

public class Major implements Serializable { // ... 其他省略 ... }

这时候测试用例完全不变,直接运行,也可以得到如下结果:

7cd2a1c4ac24c1b0b714c91705aaec45.png

75dd2b538f2640af6dce6cc15e5c189d.png

很明显,这时候student1和student2两个对象也是完全独立的,不受互相的干扰,深拷贝完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296486.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++遍历树-非递归递归-使用了标记位

//这不是最有效的方法,但使用了标记为容易理解,记下 /* * description:树的遍历示例,非递归版本 * 入栈顺序: * 前序: 右子树 - 左子树 - 当前节点 * 中序&#xff1…

模板打印函数

vector的元素可以是任意类型T,但必须具备赋值和拷贝能力(具有public 拷贝构造函数和重载的赋值操作符). 其实很容易理解,自定义一些模板时,同样会需要其实例化类型具备默写操作(如大于小于操作等。) 下面一…

各大厂抢招WPF,小米这回是下了血本啊...

九银十进入尾声,小米又爆出高薪岗位:35k左右,14薪,招5年左右.NET,要求WPF和自动化( 职位:https://app.mokahr.com/apply/xiaomi/287/#/job/523278c0-c504-4cdc-bb88-28c1b101ac76)。今年招WPF的大厂太多了&…

你永远都不知道你老公可以多幼稚......

1 爸爸带女儿!两个幼稚鬼▼2 常州一小区提醒防疫四种语言切换无压力▼3 我知道了!他的门牙肯定有条缝▼4 狗子OS:今天栏杆和木棍必须要断一个▼5 掀起你的假发来让我帮你擦擦汗▼6 干啥啥不行,吃饭第一名▼7 一看就是亲妈&…

mysql数据库属性_mysql - 数据库操作和数据属性

数据库操作启动 mysql, mac 可通过 brew 安装 mysql 后启动。 window 需要手动配置1234567891011121314mysql.server start// windownet start mysql// 登录 -u 用户名 root 超级用户 -p 密码mysql -uroot -p// 退出mysql > q// 切换到 learn 数据库mysql > use learnMyS…

jQuery中,选择器既匹配开头又匹配结尾

jQuery中,选择器既匹配开头又匹配结尾的方法: 1 [attr^val]attr$val 2 [attr^val][attr$val] 转载于:https://www.cnblogs.com/taotaodetuer/p/4790915.html

linux下解压命令大全

.tar 解包:tar xvf FileName.tar打包:tar cvf FileName.tar DirName(注:tar是打包,不是压缩!)———————————————.gz解压1:gunzip FileName.gz解压2:gzip -d…

正则基础之——神奇的转义

1 概述 这或许会是一个让人迷惑,甚至感到混乱的话题,但也正因为如此,才有了讨论的必要。 在正则中,一些具有特殊意义的字符,或是字符序列,被称作元字符,如“?”表示被修饰的子表达式匹配…

没有女朋友,可能是因为你数学不好

全世界只有3.14 % 的人关注了爆炸吧知识孔子和耶稣曾说过:初恋无限好。回想起青涩的大学时光,告别了高中时代紧张的学习氛围和父母、老师的谆谆告诫,爱情也不再是伊甸园里的禁果。关于爱情的开展和维系,在Levinger(198…

C#10,带来了Date和Time类型

C#10引入了日期DateOnly,时间TimeOnly://从DateTime转换 Console.WriteLine(DateOnly.FromDateTime(DateTime.Now)); //从字会串转换 Console.WriteLine(DateOnly.Parse("2021-10-23")); //从0001-01-01到现在的天数 Console.WriteLine(DateOn…

mysql插入时间区间_mybatis插入数据时返回主键以及MySQL根据时间区间查询问题总结...

最近做项目的过程中,在数据库方面遇到了两个问题,一是在插入一条数据的时候需要将该条数据的主键返回、二是根据时间区间进行查询时某一天的数据查询不到,在此总结记录一下。1、如何在插入一条数据的同时将主键返回在实体类的映射文件 "…

DML语言(重点)———insert

数据库的意义:数据存储,数据管理 DML语言:数据操作语言 1.insert:添加 2.update:修改 3.delete:删除 DML-添加数据 1.给指定字段添加数据 INSERT INTO 表名(字段名1,字段名2,……) VALUES(值1&#…

android下升级软件介绍

编译android: 生成:system.img,ramdisk.img,userdata.img映像文件。 ramdisk.img是emulator的文件系统 system.img包括了主要的包、库等文件 userdata.img包括了一些用户数据 emulator加载这3个映像文件后,会把 system和 userdata分别加载到 …

near far pointer

near指针的长度是16位的,所以可指向的地址范围是64K字节,通常说near指针的寻址范围是64K。far指针的长度是32位,含有一个16位的基地址和16位的偏移量,将基地址乘以16后再与偏移量相加,(所以实际上far指针是…

数据可视化----我在寻找一款类似vfp或是access这样自带可视化风格的数据库或是键盘数据库...

我在寻找一款类似vfp或是access这样自带可视化风格的数据库或是键盘数据库影响redis,mongodb今后发展的我也认为是一些可视化工具的支持http://blog.xiqiao.info/tag/data-visualization

AgileConfig 1.5 发布 - 支持多环境配置

AgileConfig 从发布到现在,收到不少同学的 issue 说需要多环境的支持。也就是一个应用在不同的环境下可以配置不同的配置项。这是一个非常有用的功能,就跟我们开发的时候会设置多个 appsettings.json 文件一样,比如 appsettings.development.…

知乎高赞:哪些事坚持做3个月就会有巨大改变?

全世界只有3.14 % 的人关注了爆炸吧知识知乎上有个高赞问题:有哪些书看完后,会让人后悔没早看到?答案各有不一、包罗万象。但有一点,大家达成了共识:要多读书。人生漫长,而我们都不会是一成不变的&#xff…

clover 主题_Clover主题更换

小白前言今天,黑果小白来教大家更换自己clover引导的 主题 ,相信大家看了这么久的主题 ,应该也厌倦了吧,换一个主题,增加一下新鲜度,废话不多说,上教程!更换前的准备要想更换主题,你就必须得有主题可以更换,没有主题,神马都是浮云&#xff01…

服务器教程笔记

1.分类。入门级(几台),工作组(50台左右),部门级(100),企业级(少数几个厂家能生产)。 2 服务器设置host 然后再apache也设置,这样就可以…

IOS使用Auto Layout中的VFL适配

做登录页面,之前做都是用frame做,今天想着用Auto Layout中的VFL来做。觉得做的效果还是可以的(自恋一下下)。 首先看下效果图和标记图 自己在做的过程中也遇到了好多问题,不过也一个一个的自己解决了 1.子视图居中的问题 上一博客我也写了,由于指定了视图的宽度高度,想让视图居…