当前位置:首页 > 经验 >

深拷贝和浅拷贝的相同点(深拷贝和浅拷贝举例)

来源:原点资讯(www.yd166.com)时间:2022-10-24 22:29:41作者:YD166手机阅读>>

前言

在阿里Java开发手册中,有这么一条建议:慎用 Object 的 clone 方法来拷贝对象。对象 clone 方法默认是浅拷贝,若想实现深拷贝需覆写 clone 方法实现域对象的深度遍历式拷贝 。Java中的对象拷贝,有浅拷贝和深拷贝两种,如果没有搞清楚这两者的区别,那么可能会给自己的代码埋下隐患。

什么是浅拷贝和深拷贝

浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

深拷贝:被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。

通过上面的结论,我们可以看出浅拷贝和深拷贝的区别就在于所要拷贝的对象的引用数据类型,如果是拷贝一份引用,那么这是浅拷贝,如果是新建一个对象,那么这就是深拷贝。

clone方法

在Java的Object对象中,有clone这个方法。它被声明为了 protected,所以我们可以在其子类中使用它。这里需要注意的是,我们在子类中使用clone方法时,子类需要实现Cloneable接口,否则会抛出java.lang.CloneNotSupportedException异常。

有如下对象

如下实体类都使用了Lombok。

Address.java

@Data public class Address { ​ private String address; ​ }

Person.java

@Data public class Person implements Cloneable { ​ private String name; ​ private Integer age; private Address address; ​ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } 浅拷贝

浅拷贝,示例代码如下:

public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.setName("Happyjava"); person.setAge(33); Address address = new Address(); address.setAddress("浙江杭州"); person.setAddress(address); Person newPerson = (Person) person.clone(); System.out.println(person == newPerson); System.out.println(person.getAddress() == newPerson.getAddress()); }

通过 == 比较是否是同一个对象。其运行结果如下:

false true

说明了通过clone方法拷贝出来的对象,与原对象并不是同一个对象。而person.getAddress() == newPerson.getAddress() 的比较是true,说明了二者的引用都是指向同一个对象。这就是浅拷贝,引用类型还是指向原来的对象。

浅拷贝存在的问题

很多时候,我们拷贝一个对象,是希望完全进行深度拷贝的。浅拷贝存在的问题就是,对于原对象引用类型的属性进行修改,拷贝出来的对象也会受到影响(因为二者的引用都指向同一个对象)。如下代码:

public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.setName("Happyjava"); person.setAge(33); Address address = new Address(); address.setAddress("浙江杭州"); person.setAddress(address); Person newPerson = (Person) person.clone(); newPerson.getAddress().setAddress("广东省深圳市"); System.out.println(person.getAddress().getAddress()); }

运行结果如下:

深拷贝和浅拷贝的相同点,深拷贝和浅拷贝举例(1)

通过newPerson把address设置为“广东省深圳市”,person的address也变成了"广东省深圳市"。

这种情况,如果我们没有注意,是很容易造成生产事故的。

深拷贝

通过clone方法实现深拷贝,是一件比较麻烦的事情,因为我们需要手动在clone方法里拷贝引用类型。代码修改如下:

Address.java

@Data public class Address implements Cloneable { ​ private String address; ​ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }

Person.java

@Data public class Person implements Cloneable { ​ private String name; ​ private Integer age; ​ private Address address; ​ @Override protected Object clone() throws CloneNotSupportedException { Person newPerson = (Person) super.clone(); newPerson.address = (Address) this.address.clone(); return newPerson; } }

通过clone方法实现深拷贝,我们需要在Person的clone方法里调用address的clone方法,并且手动设置clone出来的新的address。

再次执行上面的测试代码,运行结果如下:

深拷贝和浅拷贝的相同点,深拷贝和浅拷贝举例(2)

通过序列化实现深拷贝

通过clone方法实现深拷贝是比较麻烦的一件事情,这里推荐大家可以通过序列化、反序列化的方式实现深拷贝。我们可以直接使用commons-lang3包的序列化、反序列工具类。

引入依赖

<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.8.1</version> </dependency>

序列化需要实现Serializable接口,Person和Address类都需要实现。测试代码如下:

public static void main(String[] args) throws CloneNotSupportedException { Person person = new Person(); person.setName("Happyjava"); person.setAge(33); Address address = new Address(); address.setAddress("浙江杭州"); person.setAddress(address); // 序列化 byte[] serialize = SerializationUtils.serialize(person); // 反序列化 Person newPerson = SerializationUtils.deserialize(serialize); System.out.println(person == newPerson); System.out.println(person.getAddress() == newPerson.getAddress()); }

运行结果如下:

深拷贝和浅拷贝的相同点,深拷贝和浅拷贝举例(3)

通过结果可以看出,反序列化构建出来的对象,是全新的、深度拷贝的。

总结

拷贝对象,如果直接通过clone方法进行拷贝,是很容易出现问题的。我们要清楚的知道浅拷贝和深拷贝的区别。

原创声明

本文首发于头条号【Happyjava】,欢迎转载,但须保留此段声明。

关注获取学习资料

关注我,私信【电子书】,【视频】,即可获取大量优质电子书和大数据、kafka、nginx、MySQL等视频资料

深拷贝和浅拷贝的相同点,深拷贝和浅拷贝举例(4)

,

栏目热文

零拷贝和非零拷贝有什么区别(零拷贝通俗理解)

零拷贝和非零拷贝有什么区别(零拷贝通俗理解)

作者 | 小林coding来源 | 小林coding(ID:CodingLin)头图 | CSDN 下载自视觉中国前言磁...

2022-10-24 22:34:18查看全文 >>

深拷贝和浅拷贝的实现原理(深拷贝浅拷贝零拷贝的区别是什么)

深拷贝和浅拷贝的实现原理(深拷贝浅拷贝零拷贝的区别是什么)

用js处理数据的时候经常遇到这样一个问题,需要保留原始数据不变情况下,进行一系列数据操作,这时候需要制作一份原始数据的副...

2022-10-24 22:36:32查看全文 >>

直接复制和浅拷贝和深拷贝的区别(深拷贝与浅拷贝示意图)

直接复制和浅拷贝和深拷贝的区别(深拷贝与浅拷贝示意图)

概述今天主要来看看Python中的浅拷贝和深拷贝内容,这里用一个实例来说明~需求:将一个列表的数据复制到另一个列表中。思...

2022-10-24 22:39:34查看全文 >>

高拷贝和低拷贝的区别(深拷贝浅拷贝零拷贝的区别是什么)

高拷贝和低拷贝的区别(深拷贝浅拷贝零拷贝的区别是什么)

一、如何判断我的质粒是高拷贝还是低拷贝质粒?高拷贝质粒每 1 ml LB 培养物应产生 3-5 ug DNA,而低拷贝质...

2022-10-24 22:41:09查看全文 >>

深拷贝和浅拷贝有哪些应用

深拷贝和浅拷贝有哪些应用

大家好我是发哥,本期说说C 深拷贝和浅拷贝。对于基本类型的数据以及简单的对象,它们之间的拷贝非常简单,就是按位复制内存...

2022-10-24 22:41:01查看全文 >>

禾秆草泡水喝的功效(禾秆草图片)

禾秆草泡水喝的功效(禾秆草图片)

广东有三宝——陈皮、咸榄、禾秆草!不少“老广”都会有居家自备“三宝扎”的习惯:用陈皮包裹橄榄,再用禾秆草捆扎,置入粗盐罐...

2022-10-24 22:52:32查看全文 >>

禾秆草功效与禁忌(禾秆草有什么功能)

禾秆草功效与禁忌(禾秆草有什么功能)

广东三宝广东三宝是指:老姜、陈皮、禾秆草。前两样好理解,但是禾秆草,也就是稻草,怎么也能入选“三宝”呢?禾杆草为什么被广...

2022-10-24 22:53:23查看全文 >>

为什么稻草灰可以吃(稻草灰功效与作用)

为什么稻草灰可以吃(稻草灰功效与作用)

来源:上游新闻-重庆晨报俗话说:“民以食为天!”不同的地域特征和生活习性,烹制出不同的美味。稻草成灰,原本平凡无奇,但与...

2022-10-24 22:22:59查看全文 >>

禾麻草图片功效作用(野麻子治什么病)

禾麻草图片功效作用(野麻子治什么病)

2020年7月22日,贵州省毕节市威宁自治县,中药材一一禾麻草(荨麻)。[陶泽祥 摄影]禾麻草霍麻草禾麻荨麻,...

2022-10-24 22:16:20查看全文 >>

老姜和禾秆草功效(禾秆草的功效与作用)

老姜和禾秆草功效(禾秆草的功效与作用)

文/羊城晚报 陈辉 张华 通讯员张秋霞 李朝图/视觉中国国庆中秋双节里,举国上下一片欢腾。网友形容,8天假期像过年。外出...

2022-10-24 22:48:49查看全文 >>

文档排行