在之前的学习过程中,并没有碰到也没有学习过有关clone的知识,在准备面试题时,碰到新的知识,特此记录一下
一.为什么使用clone
在实际的编程过程中,我们常常遇到这种情况:有一个对象A ,在某个时刻A中已经包含了一些有效值,此时可能会需要一个和A 完全相同的新对象B,并且此后对B的任何改动都不会影响到A 中的值,也就是说A和B是两个独立的对象,但B的初始值是由A对象确定的,在JAVA中,用简单的赋值语句是不能满足这一要求的,要满足这种需求最简单最高效的手段就是使用clone()方法.
二.new()对象和clone()对象的区别
new和clone都可以创建对象,两者的区别总结为以下两点
- clone()不会调用构造方法,new()可以调用构造方法
- clone()能快速创建一个已有对象的副本,可以创建对象并且将已有对象的属性值克隆
new()只是在JVM中开辟申请一个空的内存区域,属性值要通过构造方法来赋值
三.浅拷贝
1.浅拷贝概念
默认的Object.clone()方法,对于引用类型成员变量拷贝"值"即地址,没有在堆中开辟新的内存空间
2.浅拷贝特点
- 对于基本数据类型的成员变量来说,浅拷贝会直接进行值传递,若对其中一个成员变量的值进行修改,不会影响另一个成员变量的值
- 对于引用类型的成员变量来说,浅拷贝会进行引用传递,将该成员变量的引用值赋值一份给新的对象,两个对象实质是指向同一个实例,若其中一个对象的值被修改,另一个也会被影响
3.浅拷贝的主要实现方式
- 通过拷贝构造方法的方式进行浅拷贝
注意: 拷贝构造犯法有且只能实现浅拷贝 - 通过重写clone()方法进行拷贝
调用Object类中的protected Object clone() throws CloneNotSupportedException
使用这个模板来实现浅拷贝
问题:
使用clone()方法必须事先Cloneable接口,否则会抛出异常
object中的这个方法是protected修饰的,我们无法直接使用
解决:
在要使用clone方法的类中重写clone()方法,通过super.clone()调用Object类中的原clone方法
4.特殊
上述论述中我们已经了解到了引用类型和基本类型的浅拷贝的区别,但是String类型非常特殊.首先,String类型属于引用数据类型,不属于基本数据类型,但是String类型数据的值是存放在常量池中的,也是无法修改的.当改变了String类型A的值,并不是修改了数据的值,而是把数据引用从A常量改变成了B常量,在这种情况下,一个对象的值改变了,另一个对象的不会受到影响.
4.深拷贝
1.深拷贝的概念
重写clone()方法,对于引用类型的成员变量,重新在堆中开辟新内存
1.深拷贝的特点
对于理解深拷贝,首先我们先了解一个概念,了解一下什么叫做对象图
对象图:一个类有一个对象,其成员变量中又有一个对象,该对象指向另一个对象,另一个对象也会继续指向另一个对象,直到得到一个确定的实例.这就是对象图
深拷贝:如果想要深拷贝一个对象,这个对象必须要实现Cloneable接口.实现clone方法,并且在clone方法内部,把该对象引用的其他对象也要clone一份,这就要求这个被引用的对象必须也要实现Cloneable接口并重写clone方法.
深拷贝简而言之就是对每一层的每个对象都进行浅拷贝(实现cloneable接口并重写方法).深拷贝无论什么类型属性的修改都不会影响另一个属性的值.