首先,明确一点深拷贝和浅拷贝是针对对象属性为对象的,因为基本数据类型在进行赋值操作时(也就是拷贝)是直接将值赋给了新的变量,也就是该变量是原变量的一个副本,这个时候你修改两者中的任何一个的值都不会影响另一个,而对于对象或者引用数据来说在进行浅拷贝时,只是将对象的引用复制了一份,也就内存地址,即两个不同的变量指向了同一个内存地址,那么在改变任一个变量的值都是该变这个内存地址的所存储的值,所以两个变量的值都会改变。

一、clone()方法

在Java中是用clone()方法实现深拷贝的,比如以下代码在Java中是很常见的

Person p = new Person(23, "zhang");Person p1 = p;System.out.println(p);System.out.println(p1);

这段代码的打印结果为:

testclone.Person@2f9ee1ac
testclone.Person@2f9ee1ac

可以看出两者打印的地址是相同的,既然地址相同那就代表两者是同一个对象,而p和p1都只是引用罢了。代码执行后,内存中的情况

而下面这段代码才是真的克隆了一个对象

Person p = new Person(23, "zhang");Person p1 = (Person) p.clone();System.out.println(p);System.out.println(p1)

打印的结果为:

testclone.Person@2f9ee1ac
testclone.Person@67f1fba0

从结果来看两者不是同一个地址,那自然就不是同一个对象,而内存情况如下

 二、深拷贝和浅拷贝

在上面的代码中Person中有两个成员变量,分别是name和age, name是String类型, age是int类型。代码非常简单,如下所示:

public class Person implements Cloneable{private int age ;private String name;public Person(int age, String name) {this.age = age;this.name = name;}public Person() {}public int getAge() {return age;}public String getName() {return name;}@Overrideprotected Object clone() throws CloneNotSupportedException {return (Person)super.clone();}
}

Person类的两个成员变量中,age是基本数据类型,关于基本数据类型的拷贝在上面就已经说过了,但是name是引用数据类型,它只是一个引用, 指向一个真正的String对象,那么对它的拷贝有两种方式: 直接将源对象中的name的引用值拷贝给新对象的name字段, 或者是根据原Person对象中的name指向的字符串对象创建一个新的相同的字符串对象,将这个新字符串对象的引用赋给新拷贝的Person对象的name字段。这两种拷贝方式分别叫做浅拷贝和深拷贝。深拷贝和浅拷贝的原理如下图所示:

下面我们通过代码来验证:如果两个Person对象的name的地址值相同, 说明两个对象的name都指向同一个String对象, 也就是浅拷贝, 而如果两个对象的name的地址值不同, 那么就说明指向不同的String对象, 也就是在拷贝Person对象的时候, 同时拷贝了name引用的String对象, 也就是深拷贝。验证代码如下:

Person p = new Person(23, "zhang");Person p1 = (Person) p.clone();String result = p.getName() == p1.getName() ? "clone是浅拷贝的" : "clone是深拷贝的";System.out.println(result);

打印的结果为:

clone是浅拷贝

也就是clone方法本身是一个浅拷贝的方法,而上一个代码我们又得出clone是深拷贝,那么是我前面写错了吗?那当然不是,clone方法本身是浅拷贝的,但是我们可以通过重写该方法来实现深拷贝 ,所以要实现深拷贝我们就需要实现Cloneable接口,覆盖并实现clone方法,除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。如果只是用Object中默认的clone方法,是浅拷贝的,再次以下面的代码验证:

static class Body implements Cloneable{public Head head;public Body() {}public Body(Head head) {this.head = head;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}}static class Head /*implements Cloneable*/{public  Face face;public Head() {}public Head(Face face){this.face = face;}} public static void main(String[] args) throws CloneNotSupportedException {Body body = new Body(new Head());Body body1 = (Body) body.clone();System.out.println("body == body1 : " + (body == body1) );System.out.println("body.head == body1.head : " +  (body.head == body1.head));}

在上述代码中有两个主要的类,Body和Face,Body类中又组合了Face对象,在对Body进行clone时,它所组合的Face对象时浅拷贝,其打印结果可以很好的证明这一点:

body == body1 : false
body.head == body1.head : true

如果要使Body对象在clone时进行深拷贝, 那么就要在Body的clone方法中,将源对象引用的Head对象也clone一份。

static class Body implements Cloneable{public Head head;public Body() {}public Body(Head head) {this.head = head;}@Overrideprotected Object clone() throws CloneNotSupportedException {Body newBody =  (Body) super.clone();newBody.head = (Head) head.clone();return newBody;}}static class Head implements Cloneable{public  Face face;public Head() {}public Head(Face face){this.face = face;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}} public static void main(String[] args) throws CloneNotSupportedException {Body body = new Body(new Head());Body body1 = (Body) body.clone();System.out.println("body == body1 : " + (body == body1) );System.out.println("body.head == body1.head : " +  (body.head == body1.head));}

打印结果为:
body == body1 : false
body.head == body1.head : false

由此可见, body和body1内的head引用指向了不同的Head对象, 也就是说在clone Body对象的同时, 也拷贝了它所引用的Head对象, 进行了深拷贝。
从以上的内容中我们可以知道,一个对象要实现深拷贝,就要实现Cloneable接口,重写clone()方法,并在clone()方法中将对象引用的其他对象也要clone一份,这就要求被引用的对象也要实现Cloneable接口,并实现clone()方法。

而按照这个结论,Body类中组合了Head类,而Head类中又组合了Face类,在对Body对象进行深拷贝时,会拷贝其中的Head类,而这时默认执行的时浅拷贝,也就是说其中的Face对象并不会被拷贝,代码如下:

static class Body implements Cloneable{public Head head;public Body() {}public Body(Head head) {this.head = head;}@Overrideprotected Object clone() throws CloneNotSupportedException {Body newBody =  (Body) super.clone();newBody.head = (Head) head.clone();return newBody;}}static class Head implements Cloneable{public  Face face;public Head() {}public Head(Face face){this.face = face;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}} static class Face{}public static void main(String[] args) throws CloneNotSupportedException {Body body = new Body(new Head(new Face()));Body body1 = (Body) body.clone();System.out.println("body == body1 : " + (body == body1) );System.out.println("body.head == body1.head : " +  (body.head == body1.head));System.out.println("body.head.face == body1.head.face : " +  (body.head.face == body1.head.face));}

打印结果为:

body == body1 : false
body.head == body1.head : false
body.head.face == body1.head.face : true

那我们可以想一想,这对Body对象来说,到底是不是深拷贝,其实是可以算的,因为Body对象中的引用对象是拷贝了的(这段代码中只有Head对象的引用),也就是说两个独立的Body对象中的Head引用指向了两个独立的Head对象,但对于Head对象来说,其Face引用指向了同一个Face对象。所以严格来说这是一种不彻底的深拷贝,而若是想要彻底的深拷贝,就要保证该对象的所有引用对象的类型都要去实现Cloneable接口,实现clone方法。

参考文献:https://blog.csdn.net/zhangjg_blog/article/details/18369201

深拷贝和浅拷贝的区别相关推荐

  1. Python基础:对象的深拷贝和浅拷贝的区别

    Python基础:对象的深拷贝和浅拷贝的区别 1 变量与对象 2 不可变对象与可变对象 3 直接赋值 4 浅拷贝 5 深拷贝 参考文献 1 变量与对象 对象:内存中存储数据的实体,有明确的类型.在Py ...

  2. python 深拷贝_详解python的复制,深拷贝和浅拷贝的区别

    概述 今天主要来看看Python中的浅拷贝和深拷贝内容,这里用一个实例来说明~ 需求: 将一个列表的数据复制到另一个列表中. 思路: 使用列表[:],拿不准可以调用copy模块. 实现方法: #!/u ...

  3. c++深拷贝和浅拷贝的区别?

    c++深拷贝和浅拷贝的区别 浅拷贝 深拷贝 总结 浅拷贝 对一个已知对象进行拷贝,编译系统会自动调用一种构造函数--拷贝构造函数,如果用户未定义拷贝构造函数,则会调用默认拷贝构造函数,调用一次构造函数 ...

  4. Python中深拷贝与浅拷贝的区别?

    往期面试题: 列举Python中的标准异常类? 说说Python面向对象三大特性? 说说Python中有几种数据类型? 说说Python模块主要分哪三类? 废话不多说,开始今天的题目: 问:说说Pyt ...

  5. python的复制,深拷贝和浅拷贝的区别

    python的复制,深拷贝和浅拷贝的区别 在python中,对象赋值实际上是对象的引用.当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用 一般有 ...

  6. C++深拷贝与浅拷贝的区别-简单易懂

    C++深拷贝与浅拷贝的区别-简单易懂 介绍 浅拷贝就比如像引用类型,而深拷贝就比如值类型. 浅拷贝是指源对象与拷贝对象共用一份实体,仅仅是引用的变量不同(名称不同).对其中任何一个对象的改动都会影响另 ...

  7. python中深拷贝与浅拷贝的区别

    ####################python中的数据类型####################### ##########python中的数据类型有6种,分别为:数字类型如int,float ...

  8. 【C++面试问答】搞清楚深拷贝与浅拷贝的区别

    问题 深拷贝和浅拷贝的区别是面试中的常见问题之一,对于不同的编程语言,这个问题的回答可能稍有差别,下面我们就来探索一下它们之间的异同吧. 先来看看在JavaScript对象的深拷贝与浅拷贝的区别: 浅 ...

  9. 如何完美解答面试问题——深拷贝和浅拷贝的区别

    大家好,我是孤焰.今天要谈一谈在面试过程中可能被面试官提到的一个问题--深拷贝和浅拷贝的区别? 由于我也是刚刚学习编程的小白,所以此篇博文将参考了多篇博文,最后总结而成. 最近由于多门考试临近,所以博 ...

  10. java -- 深拷贝和浅拷贝的区别 如何实现深拷贝和浅拷贝

    文章目录 1. 深拷贝和浅拷贝的区别 1.1 浅拷贝实例 1.1.1 测试1 直接赋值 1.1.2 测试2 改变源对象的值 1.2 深拷贝实例 `这是用于深拷贝的测试类` 1.2.1 方法一: 构造函 ...

最新文章

  1. Windows上安装Nacos
  2. YOLO发展史(v4/v5的创新点汇总!)
  3. YOLOv5x6模型来了! 同样支持CPU上ONNX部署与推理
  4. 微软发布Azure Application Insights for Node.js 1.0版本
  5. 业余无线电通信_登山与业余无线电的完美结合,便携式电台参加VHF比赛心得体会...
  6. TClientDataSet[3]: 手动建立数据集
  7. arm-none-eabi-gcc install
  8. mysql identifier name is too long_ORA-00972: identifier is too long 问题处理
  9. python数据包之利器scapy用法!
  10. 20175212童皓桢 实验三敏捷开发与XP实践实验报告
  11. 【JavaSE系列】 第九话 —— 多态那些事儿
  12. GVM 内存结构 垃圾回收
  13. [siggraph13]《命运》的实时渲染技术
  14. 什么是深度卷积神经网络,基于深度卷积神经网络
  15. java打印日期序列_Java8新特性之新日期API
  16. 灵机一动-趣味问题种种
  17. 初识EMC元器件(九)——气体放电管的参数解读及选型应用
  18. 东北话编程,大写的服!这是一个丧心病狂的Github项目!
  19. Vue3 学习总结笔记 (十四)
  20. 全屋WiFi彻底无死角 这才是终极解决方案

热门文章

  1. Prometheus监控报警系统
  2. 谷歌大中华区总裁李开复离职
  3. 低电平译码器LS138设计
  4. 命令行LOGO在线生成网站
  5. 【SeedCoder2015年 热身题5 搜索】上上下下ABAB (题目+答案)
  6. php测试页面打开速度,测试网站访问速度的五个方法
  7. java 替换 ppt内容_Java 替换PPT中的指定文本内容 详细始末
  8. 2016民用安防2.0时代重新起航
  9. react-router-dom文档
  10. 基于Java+SpringBoot+Thymeleaf+Mysql在线购物网站商城系统设计实现