JavaSE基础之“Clonable 接口和深浅拷贝”

目录

前言 

一、 Cloneable接口

 二、浅拷贝和深拷贝

1、浅拷贝

2、深拷贝


前言 

在前面有关数组的博客中,有提及到克隆clone方法.

其数组的克隆clone和本章节要介绍的实现Clonable接口的拷贝方法,有些许的不同。

拷贝后的数组,为原数组的一份拷贝副本,拷贝好后的副本和被拷贝数组的引用变量,所引用的数组不是同一个,只是内容一样,首元素地址不同。

 

有关数组的介绍传送门:

JavaSE基础(六) ---数组*_星河栀染的博客-CSDN博客Java中数组的基础知识(数组排序,逆序排序,二分查找,二维数组等等)https://blog.csdn.net/weixin_50584850/article/details/123724766?spm=1001.2014.3001.5501

一、 Cloneable接口

Java 中内置了一些很有用的接口, Cloneable 就是其中之一.

一个类实现了Cloneable接口,通过重写clone()方法来对要拷贝的对象进行拷贝。

但要十分注意的是,Cloneable接口中并没有clone()方法,也就是只能通过实现该接口来克隆对象是不可能的。

Cloneable接口源代码内是没有代码的,为空。这个接口作为一个空接口【标记接口】,代表当前类是可以被克隆的。

🤔那么此时重写的clone方法()是重写谁的呢?

  • 我们知道所有的类,其默认继承的父类都是Object类,那么在实现Cloneable接口中,使用的是公共的Object.clone()。
  • 该方法对于该类的实例进行现场复制是合法的。
  • 在不实现Cloneable接口的实例上调用对象的克隆方法导致抛出异常CloneNotSupportedException。

也就是说要通过调用Object类中的clone()方法来创建一个对象的拷贝,是要想合法调用 clone 方法, 必须要 先实现 Clonable 接口。

在Object类中的clone方法为:

该object类的clone方法,其访问修饰符是为protected,说明只有子类能调用Object类的这个方法。

子类只能调用受保护的方法来克隆它自己的对象.

其底层clone的实现,我们是看不到的。


 二、浅拷贝和深拷贝

对于“浅拷贝”和“深拷贝”,我需要知道的是。

(1)浅拷贝:

        默认的克隆操作是“浅拷贝”,其中并没有克隆对象中引用的其他对象。

        拷贝的对象中存在其他的引用对象时,进行浅拷贝则会让原对象和浅克隆对象共享同一个引用对象(该克隆后的引用对象指向的是同一个)。

修改其中一个克隆后对象中的引用对象,也会导致原对象中引用对象发生改变。

(2)深拷贝:

        深拷贝也就是在浅拷贝的基础上,重新定义为一个能同时克隆所有对象的clone方法

以一个Person类为例:

1、浅拷贝

浅拷贝示例:

 看到这个代码,你可能会有很多疑惑?

接下来将对其逐一分析。

首先我们得知道,要对一个对象进行克隆,得满足以下条件:

(1)这个对象是可以被克隆的。

(2)一个自定义类型要被克隆,前提是实现Cloneable这个接口

对于调用的clone方法, 上面说过,调用的其实是重写Object类中的clone()方法,并非是Cloneable接口自己的。我们可以通过IDEA快捷键ctrl+o,直接创建一个重写的clone方法。

 但此时,你会发现该方法中出现了一个"thorws CloneNotSupportedException"

 

🤔这又是个什么东西呢?

此处的thorws CloneNotSupportedException,是声明一个异常。(有关异常的知识,后续会整理出来)

我们知道,一个对象要被克隆,一定得实现Cloneable接口,否则会生成一个受查异常(受查异常Exception又可以叫做编译时异常)。

可在编译的时候,编译器是不知道,要被克隆的对象是否实现了该接口,因此我们要声明这个异常,让其交给上阶调用者处理,此处调用clone方法的是在main方法内,可是在main方法中,我们也没办法处理该异常,那么就再main方法中再一次声明异常thorws CloneNotSupportedException,让其交给JVM处理。如果确实出现克隆对象没有实现接口,那么在运行代码时就会出现异常.

之后通过return返回调用Object类中clone的对象即可。

🤔 但在main方法中,通过调用clone方法赋给一个新的对象,你会发现该代码出现了编译错误,这又是因为什么原因出错呢?

      💥  这是因为在上面重写的clone方法中,返回的克隆后对象的类类型是Object类,由于克隆的特殊性,我们在让一个新的对象指向克隆对象,需要将克隆对象强制转换为相对于的类类型。

             所以正确的代码应该为:

Person person1=(Person) person.clone();

 以上的拷贝可以正常对该对象进行拷贝,其内部并没有引用其他的对象。

🤔但要是克隆的对象内还引用了其他的对象结果会是什么样呢?

 可运行代码后,会发现修改了person中的引用对象,会导致person1中的引用对象也发生了修改。

如上代码,我们可以看到,通过clone,我们只是拷贝了Person对象。但是Person对象中的Student对象,并没有拷贝。通过person1这个引用修改了name的值后,person这个引用访问name的时候,值也发生了改变。这里 就是发生了浅拷贝。


2、深拷贝

💥那么要如何实现深拷贝呢?

实现深拷贝是从代码层次上来看的,不是说某个方法是深拷贝,而是从代码的实现上来看。

要想实现深拷贝,我们在进行浅拷贝的时候,也要对其拷贝对象内的引用对象进行一次拷贝,所有引用对象进行拷贝后,返回拷贝的对象即可。

具体代码实现示例:

 ​​​​​

运行结果:

 

 拷贝完成后,通过这个拷贝对象引用修改其指向的student对象的数据,原来的对象是不会改变的。

 【注意】:

如果拷贝的对象中有多个引用对象,那么要记得对这些对象也进行一遍拷贝.


 今天对Cloneable接口的深浅拷贝的分析,到这里就结束了。

又是周末肝博客的一天!

该坚持的事,还是得继续坚持下去!

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星河栀染

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值