版权声明:

本账号发布文章均来自公众号,承香墨影(cxmyDev),版权归承香墨影所有。

未经允许,不得转载。

一、前言

任何变成语言中,其实都有浅拷贝和深拷贝的概念,Java 中也不例外。在对一个现有的对象进行拷贝操作的时候,是有浅拷贝和深拷贝之分的,他们在实际使用中,区别很大,如果对其进行混淆,可能会引发一些难以排查的问题。

本文就在 Java 中的深拷贝和浅拷贝做一个详细的解说。

二、什么是浅拷贝和深拷贝

首先需要明白,浅拷贝和深拷贝都是针对一个已有对象的操作。那先来看看浅拷贝和深拷贝的概念。

在 Java 中,除了基本数据类型(元类型)之外,还存在 类的实例对象 这个引用数据类型。而一般使用 『 = 』号做赋值操作的时候。对于基本数据类型,实际上是拷贝的它的值,但是对于对象而言,其实赋值的只是这个对象的引用,将原对象的引用传递过去,他们实际上还是指向的同一个对象。

而浅拷贝和深拷贝就是在这个基础之上做的区分,如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有真实的创建一个新的对象,则认为是浅拷贝。反之,在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量,则认为是深拷贝。

所以到现在,就应该了解了,所谓的浅拷贝和深拷贝,只是在拷贝对象的时候,对 类的实例对象 这种引用数据类型的不同操作而已。

总结来说:

1、浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝。

2、深拷贝:对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容,此为深拷贝。

三、Java 中的 clone()

3.1 Object 上的 clone() 方法

在 Java 中,所有的 Class 都继承自 Object ,而在 Object 上,存在一个 clone() 方法,它被声明为了 protected ,所以我们可以在其子类中,使用它。

而无论是浅拷贝还是深拷贝,都需要实现 clone() 方法,来完成操作。

可以看到,它的实现非常的简单,它限制所有调用 clone() 方法的对象,都必须实现 Cloneable 接口,否者将抛出 CloneNotSupportedException 这个异常。最终会调用 internalClone() 方法来完成具体的操作。而 internalClone() 方法,实则是一个 native 的方法。对此我们就没必要深究了,只需要知道它可以 clone() 一个对象得到一个新的对象实例即可。

而反观 Cloneable 接口,可以看到它其实什么方法都不需要实现。对他可以简单的理解只是一个标记,是开发者允许这个对象被拷贝。

3.2 浅拷贝

先来看看浅拷贝的例子。

首先创建一个 class 为 FatherClass ,对其实现 Cloneable 接口,并且重写 clone() 方法。

然后先正常 new 一个 FatherClass 对象,再使用 clone() 方法创建一个新的对象。

最后看看输出的 Log :

I/cxmyDev: fatherA == fatherB : false
I/cxmyDev: fatherA hash : 560973324
I/cxmyDev: fatherB hash : 560938740
I/cxmyDev: fatherA name : 张三
I/cxmyDev: fatherB name : 张三

可以看到,使用 clone() 方法,从 ==hashCode 的不同可以看出,clone() 方法实则是真的创建了一个新的对象。

但这只是一次浅拷贝的操作。

来验证这一点,继续看下去,在 FatherClass 中,还有一个 ChildClass 的对象 child ,clone() 方法是否也可以正常复制它呢?改写一个上面的 Demo。

看到,这里将其内的 child 进行负责,用起来看看输出的 Log 效果。

I/cxmyDev: fatherA == fatherB : false
I/cxmyDev: fatherA hash : 560975188
I/cxmyDev: fatherB hash : 560872384
I/cxmyDev: fatherA name : 张三
I/cxmyDev: fatherB name : 张三
I/cxmyDev: ==================
I/cxmyDev: A.child == B.child : true
I/cxmyDev: fatherA.child hash : 560891436
I/cxmyDev: fatherB.child hash : 560891436

从最后对 child 的输出可以看到,A 和 B 的 child 对象,实际上还是指向了统一个对象,只对对它的引用进行了传递。

3.3 深拷贝

既然已经了解了对 clone() 方法,只能对当前对象进行浅拷贝,引用类型依然是在传递引用。

那么,如何进行一个深拷贝呢?

比较常用的方案有两种:

  1. 序列化(serialization)这个对象,再反序列化回来,就可以得到这个新的对象,无非就是序列化的规则需要我们自己来写。
  2. 继续利用 clone() 方法,既然 clone() 方法,是我们来重写的,实际上我们可以对其内的引用类型的变量,再进行一次 clone()。

继续改写上面的 Demo ,让 ChildClass 也实现 Cloneable 接口。

最重要的代码就在 FatherClass.clone() 中,它对其内的 child ,再进行了一次 clone() 操作。

再来看看输出的 Log。

I/cxmyDev: fatherA == fatherB : false
I/cxmyDev: fatherA hash : 561056732
I/cxmyDev: fatherB hash : 561057344
I/cxmyDev: fatherA name : 张三
I/cxmyDev: fatherB name : 张三
I/cxmyDev: ==================
I/cxmyDev: A.child == B.child : false
I/cxmyDev: fatherA.child hash : 561057304
I/cxmyDev: fatherB.child hash : 561057360

可以看到,对 child 也进行了一次拷贝,这实则是对 ChildClass 进行的浅拷贝,但是对于 FatherClass 而言,则是一次深拷贝。

其实深拷贝的思路都差不多,序列化也好,使用 clone() 也好,实际上都是需要我们自己来编写拷贝的规则,最终实现深拷贝的目的。

如果想要实现深拷贝,推荐使用 clone() 方法,这样只需要每个类自己维护自己即可,而无需关心内部其他的对象中,其他的参数是否也需要 clone() 。

四、总结

到现在基本上就已经梳理清楚,Java 中浅拷贝和深拷贝的概念了。

实则浅拷贝和深拷贝只是相对的,如果一个对象内部只有基本数据类型,那用 clone() 方法获取到的就是这个对象的深拷贝,而如果其内部还有引用数据类型,那用 clone() 方法就是一次浅拷贝的操作。

细说 Java 的深拷贝和浅拷贝的更多相关文章

  1. Java的深拷贝和浅拷贝

    关于Java的深拷贝和浅拷贝,简单来说就是创建一个和已知对象一模一样的对象.可能日常编码过程中用的不多,但是这是一个面试经常会问的问题,而且了解深拷贝和浅拷贝的原理,对于Java中的所谓值传递或者引用 ...

  2. Java拷贝——深拷贝与浅拷贝

    深拷贝和浅拷贝 值类型 vs 引用类型 在Java中,像数组.类Class.枚举Enum.Integer包装类等等,就是典型的引用类型,所以操作时一般来说采用的也是引用传递的方式: 但是Java的语言 ...

  3. 浅析java的深拷贝与浅拷贝

    (转自:http://www.cnblogs.com/chenssy/p/3308489.html) 首先来看看浅拷贝和深拷贝的定义: 浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值,这个方式 ...

  4. Java实现深拷贝和浅拷贝

    1.类实现Cloneable才可以进行对象拷贝 2.Cloneable只实现浅拷贝,需要实现深拷贝的必须要重写clone()方法 3.利用反序列化也可以实现深拷贝,但是反序列化耗时较长 n.浅拷贝是指 ...

  5. 【Java】深拷贝和浅拷贝

    Java中的对象拷贝(Object Copy)指的是将一个对象的所有属性(成员变量)拷贝到另一个有着相同类类型的对象中去.举例说明:比如,对象A和对象B都属于类S,具有属性a和b.那么对对象A进行拷贝 ...

  6. java基础——深拷贝和浅拷贝的区别

    浅拷贝:对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝,此为浅拷贝. 深拷贝:对基本数据类型进行值传递,对引用数据类型船舰一个新的对象,并复制内容,这是深拷贝.

  7. Java问题解读系列之IO相关---Java深拷贝和浅拷贝

    前几天和棒棒童鞋讨论Java(TA学的是C++)的时候,他提到一个浅拷贝和深拷贝的问题,当时的我一脸懵圈,感觉自己学Java居然不知道这个知识点,于是今天研究了一番Java中的浅拷贝和深拷贝,下面来做 ...

  8. 浅谈Java中的深拷贝和浅拷贝(转载)

    浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...

  9. 浅谈Java中的深拷贝和浅拷贝

    转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...

随机推荐

  1. spring aop + xmemcached 配置service层缓存策略

    Memcached 作用与使用 基本介绍 1,对于缓存的存取方式,简言之,就是以键值对的形式将数据保存在内存中.在日常业务中涉及的操作无非就是增删改查.加入缓存机制后,查询的时候,对数据进行缓存,增删 ...

  2. Java基础----jdk1.8 反射实验

    (写在最前:还没入门的搬砖工的一本正经的胡说八道) 引言:  最近做到的项目中,需要给对接方提供一个公共接口,根据对方传入的XML文件的rootelement分发调用接口,最简单的使用if-else ...

  3. 如何判断浏览器为ie10以上

    如果针对ie10 以上单独写css样式的话,ie10以上已经不提供 <!--[if ...]><![endif]--> 这种方法去操作了,所以可以用css媒体查询的方法@med ...

  4. 流行框架(angularj基础)

  5. PKM你的知识需要管理

    有一段时间没有更新技术博客了~,大脑中总感觉有点东西要写,却不知道从哪里开始写~至少写点东西,也算是一个阶段的成长 学习(充电过程).工作(知识变现过程)不是简单重复,永远都是最值得去反思.玩味的事儿 ...

  6. voa 2015 / 4 / 13

    couch potato : someone who likes to spend a lot of time sitting or lying down while watching televis ...

  7. CentOS 6.9上安装mysql-5.6.36

    CentOS 6.9上安装mysql-5.6.36 1.准备数据存放的文件系统 新建一个逻辑卷,并将其挂载至特定目录即可.这里不再给出过程. 这里假设其逻辑卷的挂载目录为/data,而后需要创建/da ...

  8. HDU 5616 Jam's balance(DP)

    题目网址:http://acm.hdu.edu.cn/showproblem.php?pid=5616 题目: Jam's balance Time Limit: 2000/1000 MS (Java ...

  9. Oracle 10gR2分析函数

    Oracle 10gR2分析函数汇总 (Translated By caizhuoyi 2008‐9‐19) 说明:  1. 原文中底色为黄的部分翻译存在商榷之处,请大家踊跃提意见:  2. 原文中淡 ...

  10. Java - static的注意点

    静态函数与静态变量无需生成对象 静态函数只能调用静态变量 装载类的时候执行静态代码块 静态函数中不能使用this /* * For test static * 2014-10-26 */ public ...