天天看点

Java 深拷贝、浅拷贝及Cloneable接口

Java 深拷贝、浅拷贝及Cloneable接口

Cloneable接口是一个标记接口,也就是没有任何内容,定义如下:

这里分析一下这个接口的用法,clone方法是在Object种定义的,而且是protected型的,只有实现了这个接口,才可以在该类的实例上调用clone方法,否则会抛出CloneNotSupportException。Object中默认的实现是一个浅拷贝,也就是表面拷贝,如果需要实现深层次拷贝的话,必须对类中可变域生成新的实例。

Object提供了一个对象拷贝的默认方法clone方法,但是该方法是有缺陷的,它提供了一种浅拷贝方式,也就是它并不会把对象所有属性全部拷贝一份,而是有选择性的拷贝,拷贝规则如下:

1、基本类型

如果变量是基本类型,则拷贝其值,比如:int、float、long等。

2、String字符串

这个比较特殊,拷贝的是地址,是个引用,但是在修改的时候,它会从字符串池(String Pool)中重新生成新的字符串,原有的字符串对象保持不变,此处可以认为String是个基本类型。

3、对象

如果变量时一个实例对象,则拷贝地址引用,也就是说此时新拷贝出的对象与原有对象共享该实例变量,不受访问权限的限制。这在Java中很疯狂,因为它突破了访问权限的定义,一个private修饰的变量,竟然可以被两个实例对象访问。复制是一个具有潜在危险的操作,因为它可能引起不是你所期望的副作用。例如,假如被复制的对象包含了一个称为obRef的引用变量,当副本创建时,副 本中的obRef如同原对象中的obRef一样引用相同的对象。如果副本改变了被obRef引用的对象的内容,那么对应的原对象也将被改变。这里是另一个 例子。如果一个对象打开一个I/O流并被复制,两个对象将可操作相同的流。而且,如果其中一个对象关闭了流,而另一个对象仍试图对I/O流进行写操作的 话,将导致错误。

Cloneable接口是一个空接口,仅用于标记对象,Cloneable接口里面是没有clone()方法,的clone()方法是Object类里面的方法!默认实现是一个Native方法

<col>

1

​<code>​protected​</code>​ ​<code>​native​</code>​ ​<code>​Object clone() ​</code>​​<code>​throws​</code>​ ​<code>​CloneNotSupportedException;​</code>​

如果对象implement Cloneable接口的话,需要覆盖clone方法(因为Object类的clone方法是protected,需要覆盖为public)

2

3

​<code>​public​</code>​ ​<code>​Object clone() ​</code>​​<code>​throws​</code>​ ​<code>​CloneNotSupportedException{​</code>​

​<code>​return​</code>​ ​<code>​super​</code>​​<code>​.clone();​</code>​

​<code>​}​</code>​

Object类里的clone()方法仅仅用于浅拷贝(拷贝基本成员属性,对于引用类型仅返回指向改地址的引用)

深拷贝需要重新覆盖Clone方法。

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

​<code>​public​</code>​ ​<code>​class​</code>​ ​<code>​testDeepClone ​</code>​​<code>​implements​</code>​ ​<code>​Cloneable {​</code>​

​<code>​public​</code>​ ​<code>​int​</code>​ ​<code>​num = ​</code>​​<code>​0​</code>​​<code>​;​</code>​

​<code>​public​</code>​ ​<code>​String str = ​</code>​​<code>​"default"​</code>​​<code>​;​</code>​

​<code>​public​</code>​ ​<code>​A a;​</code>​

​<code>​public​</code>​ ​<code>​Object clone() ​</code>​​<code>​throws​</code>​ ​<code>​CloneNotSupportedException {​</code>​

​<code>​testDeepClone o = (testDeepClone) ​</code>​​<code>​super​</code>​​<code>​.clone();​</code>​

​<code>​o.str = ​</code>​​<code>​new​</code>​ ​<code>​String(​</code>​​<code>​this​</code>​​<code>​.str);​</code>​

​<code>​o.a = (A) a.clone();​</code>​

​<code>​return​</code>​ ​<code>​o;​</code>​

​<code>​// 成员属性A必须为Cloneable的,否则无法Clone其组合的类​</code>​

​<code>​class​</code>​ ​<code>​A ​</code>​​<code>​implements​</code>​ ​<code>​Cloneable {​</code>​

 利用Serializable来实现深层复制

利用Serializable进行深拷贝的时候成员属性也必须是Serializable的,否则只返回一个引用,具体参考本人的博客: