java对象深克隆_JAVA中对象的克隆及深拷贝和浅拷贝

使用场景:

在日常的编程过程 中,经常会遇到,有一个对象OA,在某一时间点OA中已经包含了一些有效值 ,此时可能会需一个和OA完全相对的新对象OB,并且要在后面的操作中对OB的任何改动都不会影响到OA的值,也就是OA与Ob是需要完全两个独立的对象。

但OB的初始值是由对象OA确定的。在JAVA语言中,用普通的赋值语句是满足不了需求的。使用对象的clone()方法是实现克隆的最简单、也是最高效的手段。

Java的所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clone()。JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用 new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。 实现克隆可以用深拷贝和浅拷贝来实现。

深拷贝和浅拷贝的基本概念的理解:

浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的引用指向的对象,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。

深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象

通过实例看深拷贝和浅拷贝的实现和不同:

浅拷贝

class AddressNew implementsCloneable {privateString add;publicString getAdd() {returnadd;

}public voidsetAdd(String add) {this.add =add;

}public Object clone() throwsCloneNotSupportedException{return super.clone();

}

}public class StudentNew implementsCloneable{private intnumber;privateString name;publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}privateAddressNew addr;publicAddressNew getAddr() {returnaddr;

}public voidsetAddr(AddressNew addr) {this.addr =addr;

}public intgetNumber() {returnnumber;

}public void setNumber(intnumber) {this.number =number;

}public Object clone() throwsCloneNotSupportedException {return super.clone();

}

}public classJavaShallowCopy {public static void main(String [] args) throwsException{

AddressNew addr= newAddressNew();

addr.setAdd("杭州市");

StudentNew stu1= newStudentNew();

stu1.setNumber(123);

stu1.setName("s1");

stu1.setAddr(addr);

StudentNew stu2=(StudentNew)stu1.clone();

System.out.println("学生1:" + stu1.getNumber() + ",地址:" +stu1.getAddr().getAdd());

System.out.println("学生2:" + stu2.getNumber() + ",地址:" +stu2.getAddr().getAdd());

System.out.println(stu1);

System.out.println(stu2);

addr.setAdd("西湖区");//stu1.setNumber(20);//stu2.setName("s2");

System.out.println("学生1:" + stu1.getName() + ",地址:" +stu1.getAddr().getAdd());

System.out.println("学生2:" + stu2.getName() + ",地址:" +stu2.getAddr().getAdd());

}

}

运行结果:

学生1:123,地址:杭州市

学生2:123,地址:杭州市

com.songidea.StudentNew@133314b

com.songidea.StudentNew@b1bc7ed

学生1:s1,地址:西湖区

学生2:s1,地址:西湖区

从运行结果来看,stu1,stu2的解是2个不同的对象了,但是在改变了,addr的对象的地址之后,stu1,stu2的2个对象的引用对象addr的值都改变了,也就是说stu1和stu2的addr对象引用的是同一个地址,这个不是我们想要的结果,在实际的开发工作中这一块一定要特别注意,使用不当可能会使业务功能或数据造成错误或混乱,所以这个拷贝只是实现在浅拷贝,那么从我们需要的场景看需要实现深拷贝才能达到我们想要的结果,下面会通过实例来看深拷贝的2种不同的实现。

深拷贝:

class Address implementsCloneable {privateString add;publicString getAdd() {returnadd;

}public voidsetAdd(String add) {this.add =add;

}

@OverridepublicObject clone() {

Address addr= null;try{

addr= (Address)super.clone();

}catch(CloneNotSupportedException e) {

e.printStackTrace();

}returnaddr;

}

}public class Student implementsCloneable{private intnumber;privateString name;publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}privateAddress addr;publicAddress getAddr() {returnaddr;

}public voidsetAddr(Address addr) {this.addr =addr;

}public intgetNumber() {returnnumber;

}public void setNumber(intnumber) {this.number =number;

}

@OverridepublicObject clone() {

Student stu= null;try{

stu= (Student)super.clone(); //浅复制

}catch(CloneNotSupportedException e) {

e.printStackTrace();

}

stu.addr= (Address)addr.clone(); //深度复制

returnstu;

}

}public classjavaDeepCopy {public static voidmain(String args[]) {

Address addr = new Address();

addr.setAdd("杭州市");

Student stu1 = new Student();

stu1.setNumber(123);

stu1.setName("s1");

stu1.setAddr(addr);

Student stu2 = (Student) stu1.clone();

System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());

System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());

System.out.println(stu1);

System.out.println(stu2);

addr.setAdd("西湖区");

stu1.setNumber(20);

System.out.println("学生1:" + stu1.getName() + ",地址:" + stu1.getAddr().getAdd());

System.out.println("学生2:" + stu2.getName() + ",地址:" + stu2.getAddr().getAdd());

} }

运行结果:

学生1:123,地址:杭州市

学生2:123,地址:杭州市

com.songidea.Student@133314b

com.songidea.Student@b1bc7ed

学生1:s1,地址:西湖区

学生2:s1,地址:杭州市

从运行结果来看,stu1,stu2的解是2个不同的对象了,在改变了addr的对象的地址之后,stu1,stu2的2个对象的引用对象addr的值只有stu1r 改变了,也就是说stu1和stu2的addr对象引用的不是同一个地址,这个是我们想要的结果所以这个拷贝只是实现在浅拷贝,那么从我们需要的场景看,这种方式实现了深拷,达到了我们想要的结果,下面会通过实例来看深拷贝的另一种实现:通过序例化来实现深拷贝。

深拷贝序列化的实现:

class AddressSerial implementsSerializable {privateString add;publicString getAdd() {returnadd;

}public voidsetAdd(String add) {this.add =add;

}

}public class StudentSerial implementsSerializable{private intnumber;privateString name;publicString getName() {returnname;

}public voidsetName(String name) {this.name =name;

}privateAddressSerial addr;publicAddressSerial getAddr() {returnaddr;

}public voidsetAddr(AddressSerial addr) {this.addr =addr;

}public intgetNumber() {returnnumber;

}public void setNumber(intnumber) {this.number =number;

}public Object clone() throwsCloneNotSupportedException {return super.clone();

}public Object deepClone() throwsIOException,OptionalDataException,ClassNotFoundException{

ByteArrayOutputStream bo=newByteArrayOutputStream();

ObjectOutputStream oo=newObjectOutputStream(bo);

oo.writeObject(this);

ByteArrayInputStream bi=newByteArrayInputStream(bo.toByteArray());

ObjectInputStream oi=newObjectInputStream(bi);returnoi.readObject();

}

}public classjavaDeepCopySreial {public static void main(String [] args) throwsException{

AddressSerial addr= newAddressSerial();

addr.setAdd("杭州市");

StudentSerial stu1= newStudentSerial();

stu1.setNumber(123);

stu1.setName("s1");

stu1.setAddr(addr);

StudentSerial stu2=(StudentSerial)stu1.deepClone();

System.out.println("学生1:" + stu1.getNumber() + ",地址:" +stu1.getAddr().getAdd());

System.out.println("学生2:" + stu2.getNumber() + ",地址:" +stu2.getAddr().getAdd());

System.out.println(stu1);

System.out.println(stu2);

addr.setAdd("西湖区");//stu1.setNumber(20);//stu2.setName("s2");

System.out.println("学生1:" + stu1.getName() + ",地址:" +stu1.getAddr().getAdd());

System.out.println("学生2:" + stu2.getName() + ",地址:" +stu2.getAddr().getAdd());

}

}

运行结果:

学生1:123,地址:杭州市

学生2:123,地址:杭州市

com.songidea.StudentSerial@1e80bfe8

com.songidea.StudentSerial@5e9f23b4

学生1:s1,地址:西湖区

学生2:s1,地址:杭州市

从运行的结果看序例化也达到了深拷贝的场景。

参考和阅读的几偏深拷贝浅拷贝的文章:

https://www.cnblogs.com/null00/archive/2010/12/14/2065088.html

https://www.cnblogs.com/xuanxufeng/p/6558330.html

https://blog.csdn.net/baiye_xing/article/details/71788741

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

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

相关文章

python安装pyserial模块_Python使用模块Pyserial模块报

用pip安装pyserial后:sudo -H pip install pyserial,运行新建的程序,名称为serial.py,程序中用到:import serial.toos.list_ports,但总是提示ImportError:No module named tools.list_ports,在度娘一顿乱搜后,在stack…

阿里巴巴开源的通用缓存访问框架JetCache介绍

摘要: JetCache是由阿里巴巴开源的通用缓存访问框架,如果你对Spring Cache很熟悉的话,请一定花一点时间了解一下JetCache,它更好用。JetCache可以做类似Spring Cache的注解式缓存,支持TTL、多级缓存、分布式自动刷新&a…

mysql数据库的总结

https://blog.csdn.net/LanlanDeming/article/details/103786146

写速度提升20%,Elasticsearch 创始人给腾讯云发来感谢信

近日,Elasticsearch 的创始人兼首席执行官Shay Banon 向腾讯云发出了一封“特別”的邮件,专程对腾讯团队为Elasticsearch开源社区做出的贡献表示了感谢。 据了解,腾讯工程师通过提交代码,成功优化了Elasticsearch高并发写入性能&…

阿里深度学习的“金刚钻”——千亿特征XNN算法及其落地实践

摘要:随着十二点的钟声响起,无数人盯着购物车开启了一年一度的“剁手”之旅。可你有没有想过这购物狂欢的背后是什么支撑起了数据规模如此庞大的计算任务?其实不只是“双十一”,每一个用户的点击和浏览,每一件宝贝的排…

python open函数参数newline_Python open() 函数

open(file, moder, buffering-1, encodingNone, errorsNone, newlineNone, closefdT)模式描述r以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。rb以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。r打开一个文件用于读写。文件…

java访问其它服务器,一个Java Web应用程序是否可以在tomcat服务器的同一本地主机中调用另一个Java Web应用程序...

i am trying to deploy two web applications say appA and appB in same local host tomcat server and when the both the applications are up in running is it possible to call appB to appA using ajax call or redirect解决方案What you are looking for toa chieve ca…

vue推荐项目

https://github.com/Antabot/White-Jotter v人事

全球唯一:MySQL社区2018年度公司贡献奖颁给阿里云

摘要:在刚刚的Percona Live开源数据库大会上,MySQL社区委员会宣布将2018年度的MySQL社区公司贡献奖(Corporate Contributor Award)唯一颁给阿里云。图中右一为阿里云数据库RDS团队 彭立勋MySQL社区颁发次奖项是为了感谢阿里云多年…

模拟灰度传感器循迹的程序_灰度传感器的工作原理

灰度传感器是模拟传感器,有一只发光二极管和一只光敏电阻,安装在同一面上。灰度传感器利用不同颜色的检测面对光的反射程度不同,光敏电阻对不同检测面返回的光其阻值也不同的原理进行颜色深浅检测。在有效的检测距离内,发光二极管…

Docker Nexus3 maven 私服(搭建篇)

文章目录一、环境准备1. 安装docker2. 启动docker3. 拉取镜像4. 目录权限5. 创建容器6. 监控日志二、登录配置2.1. 效果验证2.2. 登录2.3. 初始化一、环境准备 1. 安装docker 使用yum命令在线安装 yum install docker2. 启动docker systemctl start docker3. 拉取镜像 doc…

这个充电宝太黑科技了,又小又不用自己带线,长见识了~

戳蓝字“CSDN云计算”关注我们哦!现如今我们出门时,手机几乎都是随身携带支付用手机,移动办公用手机,刷剧玩游戏用手机手机可以说与我们工作,生活密不可分。只不过手机频率使用如此之高,也使得用电量大增当…

逆元java_逆元 - 阿聊 - 博客园

每个数a均有唯一的与之对应的乘法逆元x,使得ax≡1(mod n) , 一个数有逆元的充分必要条件是gcd(a,n)1,此时逆元唯一存在 。逆元的含义:模n意义下,1个数a如果有逆元x,那么除以a相当于乘以x。逆元的定义&#…

QuickBI助你成为分析师——群空间自主开通嵌入第三方报表权限

摘要: 用户使用过程中经常需要将创建的仪表板嵌入至自己应用中,方便查看。目前目前高级版群空间下支持用户自助化开通报表权限,通过获取拼接Token方式后台验证更加严格,并且支持实时更新/关闭Token以保证数据安全。用户使用过程中…

如何查看一个组件的 classid是多少_万一免五(万1免5)是骗人的吗?如何查看自己的交易费率是多少?万一免五最新问题汇总!...

前言每天都会遇到很多问题,大多数问题是重复的,所以整理到公众号里,希望你们看一下,别再一遍遍问了....万一免五开户是真的吗?随着监管越来越严,可以给万一免五的券商也越来越少,只要赶在万一免…

阿里云直播转点播最佳实践

摘要: 在前不久刚刚落幕的深圳云栖大会现场,有一个直播间体验项目引起了现场参会嘉宾的关注。云栖直播间是以视频云技术为基础,为云计算从业者量身打造了一个科技直播间,让每位嘉宾都可以过一把当“网红主播”的瘾。前言在前不久刚…

假如从餐饮店的角度来看架构…

戳蓝字“CSDN云计算”关注我们哦!麦当劳作为世界快餐业的巨头之一,可以说是风靡全球圈粉无数。小编个人也是麦当劳的忠实粉丝之一。今天的文章主要就是从餐饮店的角度来讲讲的互联网技术架构发展故事。为了方便故事的讲解,我们假定创始人名称…

Maven依赖方式引用UEditor的jar包

使用UEditor时候,如果不引入相关jar包,controller.jsp就会报找不到类的错误,一些功能也无法实现。但是maven中央仓库没有这两个相关的jar包,用直接导入的方式又显得莫名其妙,那么怎么通过maven方式依赖呢? …

编译期java_java编译期和运行期

举个例子,当我们作为开发人员,在电脑上拼死拼活写了一个版本的代码,然后将代码提交到git上去,当我们用jekins或其他工具将代码从git上clone下来,使用mvn package,或者mvn intall打包的过程就叫编译期。是指…

【新功能】媒体处理MPS全新支持自适应多码率、多语言音轨

摘要: 视频内容的分发与播放已经深入了各行业的各类业务场景之中,对于视频平台而言,在不同网络状况下,都能以最优质的状况播放视频,满足用户对于观看体验的更高追求是一个不变的目标。为了更好的满足视频云客户的需求&…