浅谈关于java中的深浅拷贝

一.浅拷贝(shallow copy)


 

 

1.如何实现浅拷贝?

Object类 是所有类的直接或间接父类,Object中存在clone方法,如下

protected native Object clone() throws CloneNotSupportedException;

如果想要使一个类的对象能够调用clone方法 ,则需要实现Cloneable接口, 并重写 clone方法:

public class Student implements Cloneable{private int sno ;private String name;//getter ,setter 省略
@Overridepublic Object clone() throws CloneNotSupportedException {Student s = null;try{s = (Student)super.clone();}catch (Exception e){e.printStackTrace();}return s;}}

 

现在测试clone方法:

@Testpublic void test04() throws CloneNotSupportedException {//创建Student对象Student s1 = new Student();s1.setSno(1);s1.setName("Rye");//通过clone 拷贝一个对象Student s2 = (Student)s1.clone();System.out.println("s1:"+s1);System.out.println("s2:"+s2);System.out.println("s1 == s2 ? ==> "+(s1 == s2));}

按照预期,克隆出的对象s2中的字段值应该与s1相同,但与s1对应的对象不在同一块内存空间,结果如下:

s1:Student{sno=1, name='Rye'}
s2:Student{sno=1, name='Rye'}
s1 == s2 ? ==> false
View Code

此时如果修改 s1中的sno为2,那么会不会影响到s2中的sno呢?

//修改s1中的sno
s1.setSno(2);

结果如下:

s1:Student{sno=2, name='Rye'}
s2:Student{sno=1, name='Rye'}
View Code

 

此时看似已经完成了 copy, s1 与 s2有着自己不同的值,但如果为Student中新增了Teacher类型的成员变量,结果还是跟上面一样吗?让我们改造下代码:

public class Teacher {private int tno;private String name;//getter setter省略...  
}
public class Student  implements Cloneable{private int sno ;private String name;private Teacher teacher;//getter ,setter ,toString 省略...
@Overridepublic Object clone() throws CloneNotSupportedException {Student s = null;try{s = (Student)super.clone();}catch (Exception e){e.printStackTrace();}return s;}    
}

 

此时测试代码如下:

    @Testpublic void test02() throws CloneNotSupportedException {Student student1 = new Student();student1.setSno(1);student1.setName("Rye");Teacher teacher = new Teacher();teacher.setTno(1);teacher.setName("LinTong");student1.setTeacher(teacher);Student student2 = (Student)student1.clone();System.out.println("student1:"+student1);System.out.println("student2:"+student2);System.out.println("student1 == student2 ? ==> "+ (student1 ==student2));System.out.println("student1.teacher == student2.teacher ? ==> "+ (student1.getTeacher() ==student2.getTeacher()));}

 

运行结果如下:

student1:Student{sno=1, name='Rye', teacher=Teacher{tno=1, name='LinTong'}}
student2:Student{sno=1, name='Rye', teacher=Teacher{tno=1, name='LinTong'}}
student1 == student2 ? ==> false
student1.teacher == student2.teacher ? ==> true
View Code

 

由此可见,此时经过clone生成的student2, 与 student1.二者中的teacher字段, 指向同一块内存空间;

那么可能会有人问,这会有什么影响吗? 

我们拷贝的目的,更多的时候是希望获得全新并且值相同的对象,操作原始对象或拷贝的新对象,对彼此之间互不影响;

此时我们修改student1中teacher的tno ,如下:

//修改teacher中的 tno值为2
student1.getTeacher().setTno(2);

再次运行test:

student1:Student{sno=1, name='Rye', teacher=Teacher{tno=2, name='LinTong'}}
student2:Student{sno=1, name='Rye', teacher=Teacher{tno=2, name='LinTong'}}
student1 == student2 ? ==> false
student1.teacher == student2.teacher ? ==> true
View Code

 

此时发现,student2中的teacher的tno ,也跟着变化了.

变化的原因是:通过student1执行clone时,基本类型会完全copy一份到student2对应对象内存空间中, 但是对于Teacher对象仅仅是copy了一份Teacher的引用而已.

而student1 与 student2的引用 指向的是同一块堆内存,因此不论是通过student1或是student2修改teacher 都会影响另外一个;

通过图会更直观一些:

 

 

2.浅拷贝中引用类型的变量拷贝的是对象的引用 , 可通过如下思路解决:

Teacher类中也覆写clone方法:

    @Overrideprotected Object clone() {Teacher teacher = null;try {teacher = (Teacher)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return teacher;}

 

修改Student中的clone方法,如下:

    @Overridepublic Object clone() {Student s = null;try{s = (Student)super.clone();Teacher t = (Teacher)this.teacher.clone();s.setTeacher(t);}catch (Exception e){e.printStackTrace();}return s;}

 

此时再次运行test:

student1:Student{sno=1, name='Rye', teacher=Teacher{tno=2, name='LinTong'}}
student2:Student{sno=1, name='Rye', teacher=Teacher{tno=1, name='LinTong'}}
student1 == student2 ? ==> false
student1.teacher == student2.teacher ? ==> false
View Code

 

由此可见,在copy Student的同时 将Teacher也进行了修改,如图:

目前来看是满足了我们的需求,但是如果Teacher类中,同样也有别的引用类型 的成员变量呢?

那么就同样需要一直覆写clone方法,如果这个关系不是特多还可以接受,如果引用关系很复杂就会显得代码繁琐;

此时应该使用序列化完成深度拷贝;

 

 

二.深拷贝(deep copy)


 

使用序列化完成深拷贝

深拷贝是利用对象流,将对象序列化,再反序列化得出新的对象. 因此首先需要实现序列化接口,如下:

public class Student implements Serializable{private static final long serialVersionUID = -2232725257771333130L;private int sno ;private String name;private Teacher teacher;
  //getter ,setter,toString()省略... }

Teacher也要实现序列化接口:

public class Teacher implements Serializable{private static final long serialVersionUID = 4477679176385287943L;private int tno;private String name;
  
 //getter ,setter,toString()省略...
}

 

工具方法:

  //工具方法public Object cloneObject(Object object) throws IOException, ClassNotFoundException {//将对象序列化ByteArrayOutputStream outputStream = new ByteArrayOutputStream();ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);objectOutputStream.writeObject(object);//将字节反序列化ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);Object obj = objectInputStream.readObject();return obj;}

 

测试类:

   public void test05() throws IOException, ClassNotFoundException {Student student1 = new Student();student1.setSno(1);student1.setName("Rye");Teacher teacher = new Teacher();teacher.setTno(1);teacher.setName("LinTong");student1.setTeacher(teacher);Student student2 = (Student)cloneObject(student1);//修改teacher中的 tno值为2student1.getTeacher().setTno(2);System.out.println("student1:"+student1);System.out.println("student2:"+student2);System.out.println("student1 == student2 ? ==> "+ (student1 ==student2));System.out.println("student1.teacher == student2.teacher ? ==> "+ (student1.getTeacher() ==student2.getTeacher()));}

 

如果Teacher类或者Student类没有实现序列化接口,则执行时会报异常,如下:

java.io.NotSerializableException: com.example.test.Teacher

 

在都实现了Serializable接口的情况下,运行结果如下:

student1:Student{sno=1, name='Rye', teacher=Teacher{tno=2, name='LinTong'}}
student2:Student{sno=1, name='Rye', teacher=Teacher{tno=1, name='LinTong'}}
student1 == student2 ? ==> false
student1.teacher == student2.teacher ? ==> false
View Code

 

由此通过对象流的方式,成功完成了深度拷贝;

 


 

三.重写clone方法 与 通过序列化 两种拷贝方式比较:

clone方法:

优点:速度快,效率高

缺点:在对象引用比较深时,使用此方式比较繁琐

 

通过序列化:

优点:非常简便的就可以完成深度copy

缺点:由于序列化的过程需要跟磁盘打交道,因此效率会低于clone方式

 

如何抉择?

实际开发中,根据两种方式的优缺点进行选择即可!

 

转载于:https://www.cnblogs.com/lzzRye/p/9459465.html

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

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

相关文章

iOS开发-Protocol协议及委托代理(Delegate)传值

前言:因为Object-C是不支持多继承的,所以很多时候都是用Protocol(协议)来代替。Protocol(协议)只能定义公用的一套接口,但不能提供具体的实现方法。也就是说,它只告诉你要…

git 查看分支编码_12个常用的Git命令,赶紧记一波!

今天齐姐简单讲下 Git 的实现原理,知其所以然才能知其然;并且梳理了日常最常用的 12 个命令,分为三大类分享给你。本文的结构如下:作者和开发原由Git 的数据模型常用命令资源推荐作者和开发原由Talk is cheap. Show me the code.这…

在域环境下搭建samba服务器

环境:samba:smbserver: 192.168.0.18AD:rise.com:192.168.0.37组:zixun xingzheng teacher class admin共享目录:zixun xingzheng xueshu other一.安装Samba服务器yum install -y samba二.把linux加入到ad中1.先…

Android NDK编程,引入第三方.so库

android自带的编译工具NDK进行编译时(非单纯的调用第三方.so而是进行ndk编程),armeabi以及armeabi-v7a文件夹下的第三方so文件将会被删除,只会产生编译后的so文件,其他的so文件将无法引入,现在我们就来解决&#xff1a…

会做饭的机器人曰记_颜真卿《麻姑仙坛记》:苍劲古朴,体态沉雄,气象宏大...

《麻姑仙坛记》,全称《有唐抚州南城县麻姑山仙坛记》,或称《麻姑山仙坛记》。颜真卿撰并书于大历六年(771)四月。此碑有大、中、小三种刻本,且原石均佚,原拓佳本亦难得。大字本,字径约5厘米&…

IBM服务器硬盘出现Other Error可能原因

除了确实物理等因素外,可能还因为:Other Errors的 很有可能也是固件(firmware)版本太低造成。 固件版本太低的话,硬盘自身有power safe模式,在硬盘长时间没有I/O情况下,硬盘会自动断电,而系统本身误以为是硬…

怪异模式

众所周知,HTML文档结构可分为:文档声明<!DOCTYPE HTML>、HTML元素&#xff08;根元素/根标记/根标签/祖先元素&#xff09;、head元素、body元素。 文档声明是用来通知浏览器&#xff0c;目前的文档正使用哪个HTML版本&#xff0c;如果我们不写文档声明<!DCOTYPE HTML…

Metro UI 菜单(Winform)

我有个项目需要要到菜单导航&#xff0c;就自己动作做了一个&#xff0c;感觉还可以&#xff0c;分享给大家。下载地址:http://files.cnblogs.com/files/dyj057/MetroUIMenu.zip 主要代码&#xff1a; private void SetElements(){if (Elements null) return;int eWidth Bord…

echarts 山东地图_用Python画中国地图,实现各省份数据可视化

第一步&#xff1a;安装pyechartspyecharts是一款将python与echarts结合的强大的数据可视化工具&#xff0c;本文使用了0.1.9.4版本pip install pyecharts0.1.9.4第二步&#xff1a;读取数据我的数据是在Excel表格里&#xff0c;如下图&#xff1a;Execel数据使用xlrd(没有就通…

mysql 中某个字段相同的数据拼接起来

2019独角兽企业重金招聘Python工程师标准>>> mysql> select name, GROUP_CONCAT( age SEPARATOR ‘#’) from student group by name; ——————————————————— | name | GROUP_CONCAT( age SEPARATOR ‘#’) | ———————————————…

微信红包系统架构的设计和优化分享

微信红包系统架构的设计和优化分享 编者按&#xff1a;经过2014年一年的酝酿&#xff0c;2015微信红包总量创下历史新高&#xff0c;峰值1400万次/秒&#xff0c;8.1亿次每分钟&#xff0c;微信红包收发达10.1亿次&#xff0c;系统整体运行平稳, 在这里我分享下微信红包背后的技…

Jquery各版本下载

jquery-2.1.4 (注&#xff01;jquery-2.0以上版本不再支持IE 6/7/8) 百度引用地址 (推荐目前最稳定的&#xff0c;不会出现延时打不开情况) 百度压缩版引用地址: <script src"http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> 微软压缩版引…

python list方法操作_Python 列表(List)操作方法详解

参考文献来源于脚本之家列表是Python中最基本的数据结构&#xff0c;列表是最常用的Python数据类型&#xff0c;列表的数据项不需要具有相同的类型。列表中的每个元素都分配一个数字 - 它的位置&#xff0c;或索引&#xff0c;第一个索引是0&#xff0c;第二个索引是1&#xff…

FastDFS单机版安装教程

安装清单如下&#xff1a; 一、安装FastDFS 1. 安装libfastcommon 先解压安装包到目录 # unzip libfastcommon-1.0.36.zip 安装编译工具及环境&#xff08;后面Nginx也会用到这些依赖环境&#xff09; # yum -y install gcc gcc gcc-c openssl openssl-devel pcre pcre-deve #…

【原创】Chrome最新版(53-55)再次爆出BUG!

2019独角兽企业重金招聘Python工程师标准>>> 前言 今年十月份&#xff0c;我曾发布一篇文章《Chrome53 最新版惊现无厘头卡死 BUG&#xff01;》&#xff0c;不过那个BUG在最新的 Chrome 54 中已经修正。 而今天即将发布的Chrome弱智BUG&#xff1a; 仅 Chrome 53 -…

ThinkPHP 发送post请求

function post($url, $paramarray()){ if(!is_array($param)){ throw new Exception("参数必须为array"); } $httph curl_init($url); curl_setopt($httph, CURLOPT_SSL_VERIFYPEER, 0); curl_setopt($httph, CURLOPT_SSL_VERIFYHOST, 1); curl_setopt($httph,CURLOP…

vue 打包路由报错_Vue下路由History模式打包后页面空白的解决方法

vue的路由在默认的hash模式下,默认打包一般不会有什么问题,不过hash模式由于url会带有一个#,不美观,而且在微信分享,授权登录等都会有一些坑.所以history模式也会有一些应用场景.新手往往会碰到history模式打包后页面一片空白的情况,而且没有资源加载错误的报错信息.这个其实仔…

leetcode-回文链表

请判断一个链表是否为回文链表。 示例 1: 输入: 1->2 输出: false 示例 2: 输入: 1->2->2->1 输出: true进阶&#xff1a;你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题&#xff1f; 思路&#xff1a;先遍历链表&#xff0c;获得长度。 把前半部分的链表逆置…

进程kswapd0与events/0消耗大量CPU的问题

http://www.nowamagic.net/librarys/veda/detail/2539 今天下午网站宕了两次机&#xff0c;发工单给阿里云&#xff0c;发现原因是服务器的CPU 100%了。 重启服务器后&#xff0c;使用 top 命令看看是哪些进程消耗那么大的 CPU 使用。盯了有好十几分钟&#xff0c;主要消耗 CPU…

索引器

namespace _03{ class Program { //请编写一个类&#xff1a;ItcastClass,该类中有一个私有字段_names,数据类型为&#xff1a;字符串数组&#xff0c;长度为5&#xff0c;并且有5个默认的姓名。 //要求&#xff1a;为ItcastClass类编写一个索引器&#xff0c;要求该索引器能够…