首页 > 编程知识 正文

浅拷贝和深拷贝的方法java,赋值浅拷贝深拷贝的区别

时间:2023-05-05 01:41:50 阅读:32033 作者:3129

一、前言

不管变成什么语言,其实都有浅拷贝和深拷贝的概念,Java也不例外。 复制操作现有对象时,有浅副本和深副本之分。 他们在实际使用中存在很大的差异,如果将其混淆,可能会引起难以排除的问题。

本文详细介绍了Java的深度拷贝和轻拷贝。

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

首先,必须了解浅拷贝和深拷贝都是对现有对象的操作。 首先,让我们来看看浅拷贝和深拷贝的概念。

除了基本数据类型(元类型)之外,Java还具有名为类的实例对象的引用数据类型。 一般来说,将“=”符号用于赋值操作时。 对于基本数据类型,实际上是复制的该值,但对于对象,实际上只有该对象的引用被赋值,即使传递了对原始对象的引用,实际上也指向同一对象。

浅副本和深副本据此加以区分。 复制此对象时,只复制基本数据类型,引用并传递引用数据类型;如果没有实际创建新对象,则视为浅副本。 相反,如果在复制引用数据类型时创建了新对象并复制了其中的成员变量,则将其视为深度复制。

所以现在应该理解,浅副本和深副本只是引用数据类型的不同操作,即在复制对象时类的实例对象。

总的来说:

1、浅拷贝:对基本数据类型进行传值,对引用数据类型进行类似于引用传递的拷贝。 这是浅拷贝。

2、深度复制:对基本数据类型进行传递,对引用数据类型创建新对象,并复制其内容。 这就是深拷贝。

三. Java的克隆(

3.1对象上的clone ()方法

在Java中,所有Class都是从Object继承的,但Object具有声明为protected的clone ()方法,因此可以在子类中使用。

无论是浅拷贝还是深拷贝,都必须实现clone ()方法才能完成操作。

此实现非常简单,因为它限制了调用clone (方法的所有对象都必须实现Cloneable接口,否则会抛出一个名为CloneNotSupportedException的异常最终,将调用internalClone ()方法以完成特定操作。 internalClone (方法实际上是朴素方法。 没有必要对此进行深入思考。 clone (只要知道对象可以获取新的对象实例就可以了。

相反,在Cloneable界面中,您会发现实际上不需要以任何方式来实现。 他能轻易理解的只是一个标记,允许开发人员复制这个对象。

3.2轻拷贝

我们先来看看浅拷贝的例子。

首先,将class创建为FatherClass,实现Cloneable接口,然后重写clone ()方法。

然后,在常规new上创建FatherClass对象,然后使用clone ()方法创建新对象。

请看最后输出的Log :

I/cxmydev : fathera==fatherb : false

I/cxmydev : fatherahash :560973324

I/cxmydev : fatherbhash :560938740

I/cxmyDev: fatherA name :糟糕的衬衫/pi/cxmydev : father bname :糟糕的衬衫/p显示,使用clone ()方法时,==和hashCode

但是,这是浅拷贝的操作。

请验证这个,继续看。 FatherClass还有另一个ChildClass的对象child。 clone (方法也可以正常复制吗? 重写上面的Demo。

你看,这里负责其中的child,用它来看看输出的Log效果吧。

I/cxmydev : fathera==fatherb : false

I/cxmydev : fatherahash :560975188

I/cxmydev : fatherbhash :560872384

I/cxmyDev: fatherA name :糟糕的衬衫/pi/cxmydev : father bname :糟糕的衬衫/pi/cxmydev :========

I/cxmydev : a.child==b.child : true

I/cxmy

Dev: fatherA.child hash : 560891436

I/cxmyDev: fatherB.child hash : 560891436

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

3.3 深拷贝

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

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

比较常用的方案有两种:

序列化(serialization)这个对象,再反序列化回来,就可以得到这个新的对象,无非就是序列化的规则需要我们自己来写。

继续利用 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 : 糟糕的衬衫/p>

I/cxmyDev: fatherB name : 糟糕的衬衫/p>

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() 方法就是一次浅拷贝的操作。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。