java clone

深拷贝(deep clone) 与 浅拷贝(shallow clone)

深复制 与 浅复制 概念

– 深复制(深克隆):被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。 那些引用引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象 。换而言之,

深复制把要复制的对象所引用的对象都复制了一遍。

– 浅复制(浅克隆):被复制对象的所有变量都含有与原来的对象 相同的值 ,而所有的对其他对象的引用 仍然指向原来的对象 。换而言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。

java 的 clone() 方法 【定义在Object类中】

– clone 方法将对象复制了一份并返回给调用者。

一般而言,clone()方法 满足:

   --1). 对任何的对象X, 都有x.clone()!= x

       -- **克隆对象与原对象不是同一个对象**

   --2). 对任何的对象X,都有 x.clone().getClass() == x.getClass()

       -- 克隆对象与原对象的类型一样

   --3). 如果对象X.equals() 方法定义恰当,那么x.clone().equals(x) 应该是成立。

java 中对象的克隆

– 1). 为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。

– 2). 在派生类中覆盖基类的clone()方法,并声明为 public【 Object类中的** clone()方法为protected **的 】。

– 3). 在派生类的clone()方法中,调用super.clone()**.**

– 4). 在派生类中实现Cloneable接口。

说明:

–1). 为什么我们在派生类中覆盖Object的clone() 方法时,一定要调用super.clone() 呢?

在运行时刻,Object中的clone() 识别出你要复制的是哪一个对象,然后为此对象分配空间,

并进行对象的复制,将原对象的内容一一复制到新的对象的存储空间中。

–2). 继承自 java.lang.Object 类的clone() 方法是浅复制

现在存在一个问题,一个对象里存在另一个对象的引用,我们重写对象中的clone() 方法就能实现浅克隆或深克隆。

写一次代码就能搞定,假如一个对象中存在多个对象的引用该怎么处理。

这个问题我们这么解决

利用序列化来做深复制

把对象写到流里的过程是序列化( **serialization** )过程,而把对象从流中读出来的过程则叫做反序列化( **Deserialization** )过程应当指出的是,写在流里的是对象的一个拷贝,而原对象任然存在于JVM里面。

在Java 语言里深复制一个对象,常常可以使对象实现Serialization 接口,然后把对象(实际上只是对象的一个深拷贝)写到一个流里,再从流里读出来,便可以重建对象。

– 这样做的前提是对象以及对象内部所有引用到的对象 都是可串行化** ( 串行化:就是可序列化的意思 ) 的,否则,就需要仔细考察那些不可串行化的对象可否设成 transient**,从而将之排除在复制过程之外。

注意: Cloneable 与 Serializable 都是marker Interface,也就是说他们只是一个标识接口,没有定义任何方法。

当一个类实现了Serializable 接口时,表明该类可被序列化,这个时候Eclipse会要求你为该类定义一个字段,

该字段名字为 serial Version UID, 类型为long, 提示信息如下

你可以随便写一个,在Eclipse中它替你生成一个,有两种方式:

--1). 一个是默认的1L , 比如: private static final long serialVersionUID = 1L;

--2). 一个是很据类名、接口名、成员方法及属性等来生成一个64位的哈希字段, 比如:

      private static final long serialVersionUID = 8940196742313994740L; 之类的。

如果你没有考虑到兼容性问题时,就把它关掉,不过有这个功能是好的,只要任何类别实现了Serializable这个接口的话,如果没有加入serialVersionUID,eclipse都会给你warning提示,这个serialVersionUID为了让该类别Serializable 向后兼容

什么是** 向后兼容性?**

—- 如果你的对象序列化后存到硬盘上面后,可是后来你却更改了类的field(增加或减少或改名),

当你反序列化时,就会出现Exception,这样会造成不兼容性的问题

—- 但当serialVersionUID 相同时,它就会将不一样的field以type的缺省值Deserialize,

这个可以避开不兼容性的问题