文章目录

  • 简介
  • 拷贝接口
  • 使用clone导致的浅拷贝
  • 使用clone的深拷贝
  • 不要overridden clone
  • 总结

简介

拷贝对象是java中经常会遇到的问题。java中存在两种类型,基础类型和引用类型。

java的赋值都是传值的,对于基础类型来说,会拷贝具体的内容,但是对于引用对象来说,存储的这个值只是指向实际对象的地址,拷贝也只会拷贝引用地址。

因为引用对象的存在,所以经常会出现和预期不一样的情况。

本文将会深入的探讨一下在拷贝对象中会出现的浅拷贝和深拷贝的情况。

拷贝接口

java中所有的对象都是继承自java.lang.Object。Object对象中提供了一个clone方法,来供我们对java对象进行拷贝。

    protected native Object clone() throws CloneNotSupportedException;

这个clone方法是native的,所以不需要我们来实现,但是注意clone方法还是protected,这意味着clone方法只能在java.lang包或者其子类可见。

如果我们想要在一个程序中调用某个对象的clone方法则是不可以的。因为clone方法是定义在Object中的,该对象并没有对外可见的clone方法。

JDK的建议是让我们去实现接口Cloneable,实现了这个接口就表示这个对象可以调用Object的clone方法。

注意,即使你实现了Cloneable接口,还是无法在外部程序中调用该对象的clone方法:

public interface Cloneable {}

因为Cloneable是空的,明没有强制要你去实现clone方法。

这是JDK在设计上的问题,导致clone方法并不像预期那么好用。

首先clone只是对象的拷贝,它只是简单的拷贝对象,而不会去执行对象的构造函数。

其次clone会导致浅拷贝的问题。

使用clone导致的浅拷贝

我们举个clone产生的浅拷贝的例子,我们定义一个对象中的对象,然后尝试拷贝:

@Data
public class Address implements Cloneable{private String name;//不是好的方式@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}
@Data
public class CustUser implements Cloneable{private String firstName;private String lastName;private Address address;private String[] cars;@Overridepublic Object clone() throws CloneNotSupportedException{return super.clone();}
}

上面的例子中,我们定义了CustUser和Address。

 public void testShallowCopy() throws CloneNotSupportedException {Address address= new Address();address.setName("北京天安门");CustUser custUser = new CustUser();custUser.setAddress(address);custUser.setLastName("李");custUser.setFirstName("雷");String[] cars = new String[]{"别克","路虎"};custUser.setCars(cars);CustUser custUserCopy=(CustUser) custUser.clone();custUserCopy.setFirstName("梅梅");custUserCopy.setLastName("韩");custUserCopy.getAddress().setName("北京颐和园");custUserCopy.getCars()[0]="奥迪";log.info("{}",custUser);log.info("{}",custUserCopy);}

浅拷贝我们只调用了CustUser的clone方法。看下输出结果:

CustUser(firstName=雷, lastName=李, address=Address(name=北京颐和园), cars=[奥迪, 路虎])CustUser(firstName=梅梅, lastName=韩, address=Address(name=北京颐和园), cars=[奥迪, 路虎])

我们可以看到拷贝之后的Address变化会影响到被拷贝的对象。

上面的例子我们还要关注两个点:第一点String是不可变的。不管是拷贝还是赋值,String都是不可变的。

第二点,上面的例子中我们定义了一个数组,可以看到如果只是调用clone的话,数组也是浅拷贝。

使用clone的深拷贝

要使用深拷贝,只需要修改CustUser的构造函数就可以了:

//不是很好的使用方式@Overridepublic Object clone() throws CloneNotSupportedException{CustUserDeep custUserDeep=(CustUserDeep)super.clone();custUserDeep.address=(Address)address.clone();custUserDeep.cars=cars.clone();return custUserDeep;}

在重写的clone方法中,我们分别调用了CustUser,Address和数组的clone方法来进行拷贝。

再运行一次上面的测试代码:

CustUserDeep(firstName=雷, lastName=李, address=Address(name=北京天安门), cars=[别克, 路虎])CustUserDeep(firstName=梅梅, lastName=韩, address=Address(name=北京颐和园), cars=[奥迪, 路虎])

可以看到address和cars是不同的,这表示我们的深拷贝是成功的。

不要overridden clone

上面的例子我们是通过overridden Object的clone方法来实现的。

但是最佳实践是不要overridden clone。那我们怎么做呢?

使用构造函数来构建新的对象:

    //好的方式Address(Address address){this.name=address.name;}
//很好的方式CustUserDeep(CustUserDeep custUserDeep){this.firstName=custUserDeep.firstName;this.lastName=custUserDeep.lastName;this.cars=custUserDeep.getCars().clone();this.address=new Address(custUserDeep.getAddress());}

据说数组直接用clone来拷贝会更快,也可以使用下面的方式来拷贝数组:

this.cars= Arrays.copyOf(custUserDeep.getCars(),custUserDeep.getCars().length);

总结

本文讲解了浅拷贝和深拷贝的应用,并对clone方法做了深入的探讨。

本文的例子https://github.com/ddean2009/learn-java-base-9-to-20

更多精彩内容且看:

  • 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
  • Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
  • Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
  • java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程

本文作者:flydean程序那些事

本文链接:http://www.flydean.com/java-base-shallow-copy-deep-copy/

本文来源:flydean的博客

欢迎关注我的公众号:程序那些事,更多精彩等着您!

java深入理解浅拷贝和深拷贝相关推荐

  1. 【转】JAVA中的浅拷贝和深拷贝

    原文网址:http://blog.bd17kaka.net/blog/2013/06/25/java-deep-copy/ JAVA中的浅拷贝和深拷贝(shallow copy and deep co ...

  2. java 对象深拷贝_java深入理解浅拷贝和深拷贝

    简介 拷贝对象是java中经常会遇到的问题.java中存在两种类型,基础类型和引用类型. java的赋值都是传值的,对于基础类型来说,会拷贝具体的内容,但是对于引用对象来说,存储的这个值只是指向实际对 ...

  3. clone是深拷贝还是浅拷贝_Cloneable接口的作用与探索理解浅拷贝与深拷贝

    导读:本文将主要讨论设计模式--原型模式中,关于cloneable接口及浅拷贝与深拷贝的概念. 原型模式的理解 关于原型模式的理解,我在网上发现一个有趣且助于理解原型模式的例子在这里分享一下:火影忍者 ...

  4. 理解浅拷贝和深拷贝以及实现方法

    一.数据类型 数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和引用数据类型Object,包含(function,Array,Da ...

  5. Java中的浅拷贝与深拷贝

    一.引用拷贝与对象拷贝 class Person implements Cloneable{private String name;private int age;...省略get和set方法 pro ...

  6. 让你彻底理解浅拷贝和深拷贝的区别

    在写js的时候经常会遇到复制对象,在复制对象的过程中往往会出现新对象改变原对象等等的一些问题,今天特意梳理一下,希望能帮助到遇到这些问题的开发人员. 什么是浅拷贝,深拷贝以及和他们之间的区别 赋值 浅 ...

  7. mysql浅拷贝_深入理解浅拷贝和深拷贝

    0x01:概述 Java中的对象拷贝 ( Object Copy ) 是指将一个对象的所有属性(成员变量)拷贝到另一个有着相同类类型的对象中去.例如,对象 A 和对象 B 都属于类 S,具有属性 a ...

  8. 夯实Java基础系列28:java里的浅拷贝、深拷贝

    假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...

  9. Java浅拷贝和深拷贝的方式

    文章目录 1. 前言 2. 概念介绍 2.1 拷贝 / 克隆的概念 2.2 为什么需要拷贝方法? 2.3 什么是浅拷贝?浅拷贝和深拷贝的区别是什么? 3. 深拷贝的实现方式 3.1 手动深拷贝 3.2 ...

最新文章

  1. 移动磁盘格式化了,要如何寻回数据
  2. 景驰无人车总部落户广州:明年最低量产500辆,回应百度官司
  3. 说说面向对象的故事,主人是人类!(三)
  4. 帮助类之自动解析表达式判定结果方法类
  5. jQuery封装的选项卡方法
  6. php如何接受用户邮箱发送信息,怎么将用户购物车的产品发送到邮箱
  7. winmail邮件服务器的搭建,搭建Winmail邮件系统
  8. easy touch5.0.17的安装与使用
  9. 80 - 抓取豆瓣音乐排行榜
  10. galgame序列号怎么查看_国行Switch能完整体验的游戏有哪些?Switch支架掉了怎么办? | Jump指南...
  11. usaco Typo
  12. PYTHON开发对接短信语音验证码接口
  13. Imagepy图像处理框架中neighbors函数的探索之旅
  14. 无论LCD和OLED显示技术有多好,都无法替代这个古老的显示数码管
  15. 论文阅读笔记:Multi-model Databases: A New Journey to Handle the Variety of Data
  16. 【Elasticsearch源码】 检索分析
  17. 活动报名发布小程序源码 聚会活动报名小程序完整版前端+后台管理Think
  18. 计算机毕业设计Java学生公寓管理系统(源码+系统+mysql数据库+lw文档
  19. mpt3工具箱学习记录--day2
  20. 安装redis及redis集群及解决连接不上redist问题

热门文章

  1. Three.js之渲染器
  2. OD+IDA6.1破解HideWizardv9.29(无忧隐藏)
  3. Android low memory killer 机制
  4. Error:java: 无效的标记 -version 编译错误的解决办法
  5. 经典|深入理解 Go高性能网络编程模型
  6. 多图 | 操作系统中,进程与线程怎么设计的?
  7. Kafka解惑之时间轮(TimingWheel)
  8. 设计模式:观察者模式(Observer)
  9. Java类加载器(一)——类加载器层次与模型
  10. 北京冬奥黑科技; 揭秘虎年春晚硬核科技;全球首款AR隐形眼镜问世;索尼3D显示技术路径曝光...