目录
前言
一、 Cloneable接口
二、浅拷贝和深拷贝
1、浅拷贝
2、深拷贝
在前面有关数组的博客中,有提及到克隆clone方法.
其数组的克隆clone和本章节要介绍的实现Clonable接口的拷贝方法,有些许的不同。
拷贝后的数组,为原数组的一份拷贝副本,拷贝好后的副本和被拷贝数组的引用变量,所引用的数组不是同一个,只是内容一样,首元素地址不同。
有关数组的介绍传送门:
JavaSE基础(六) ---数组*_星河栀染的博客-CSDN博客Java中数组的基础知识(数组排序,逆序排序,二分查找,二维数组等等)https://blog.csdn.net/weixin_50584850/article/details/123724766?spm=1001.2014.3001.5501
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)这个对象是可以被克隆的。
(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的时候,值也发生了改变。这里 就是发生了浅拷贝。
那么要如何实现深拷贝呢?
实现深拷贝是从代码层次上来看的,不是说某个方法是深拷贝,而是从代码的实现上来看。
要想实现深拷贝,我们在进行浅拷贝的时候,也要对其拷贝对象内的引用对象进行一次拷贝,所有引用对象进行拷贝后,返回拷贝的对象即可。
具体代码实现示例:
运行结果:
拷贝完成后,通过这个拷贝对象引用修改其指向的student对象的数据,原来的对象是不会改变的。
【注意】:
如果拷贝的对象中有多个引用对象,那么要记得对这些对象也进行一遍拷贝.
今天对Cloneable接口的深浅拷贝的分析,到这里就结束了。
又是周末肝博客的一天!
该坚持的事,还是得继续坚持下去!