淺克隆
概念:在淺克隆中袄琳,如果原型對(duì)象的成員變量是基本數(shù)據(jù)類型前翎,將復(fù)制一份給克隆對(duì)象;如果原型對(duì)象的成員變量是引用類型(類桑阶,接口等非基本類型)榔组,則將引用對(duì)象的地址復(fù)制一份給克隆對(duì)象熙尉,也就是說原型對(duì)象和克隆對(duì)象的成員變量指向相同的內(nèi)存地址。
-
實(shí)現(xiàn)步驟:
- 被復(fù)制的類需要實(shí)現(xiàn)Clonenable接口(不實(shí)現(xiàn)的話在調(diào)用clone方法會(huì)拋出CloneNotSupportedException異常)搓扯, 該接口為標(biāo)記接口(不含任何方法)
- 覆蓋clone()方法检痰,訪問修飾符設(shè)為public。方法中調(diào)用super.clone()方法得到需要的復(fù)制對(duì)象锨推。(native為本地方法)
深克隆
概念:在深克隆中铅歼,無論原型對(duì)象的成員變量是值類型還是引用類型,都將復(fù)制一份給克隆對(duì)象换可,深克隆將原型對(duì)象的所有引用對(duì)象也復(fù)制一份給克隆對(duì)象椎椰。
-
實(shí)現(xiàn)步驟:
- 實(shí)現(xiàn)Clonenable
- 被復(fù)制的類需要實(shí)現(xiàn)Clonenable接口(不實(shí)現(xiàn)的話在調(diào)用clone方法會(huì)拋出CloneNotSupportedException異常), 該接口為標(biāo)記接口(不含任何方法)
- 覆蓋clone()方法沾鳄,訪問修飾符設(shè)為public慨飘。方法中調(diào)用super.clone()方法得到需要的復(fù)制對(duì)象,再對(duì)對(duì)象中的非基本數(shù)據(jù)類型進(jìn)行復(fù)制译荞。(native為本地方法)
- 通過序列化(Serialization)等方式:如果引用類型里面還包含很多引用類型瓤的,或者內(nèi)層引用類型的類里面又包含引用類型,使用clone方法就會(huì)很麻煩吞歼。這時(shí)我們可以用序列化的方式來實(shí)現(xiàn)對(duì)象的深克隆
- 實(shí)現(xiàn)Clonenable
public class Outer implements Serializable{
private static final long serialVersionUID = 369285298572941L; //最好是顯式聲明ID
public Inner inner;
//Discription:[深度復(fù)制方法,需要對(duì)象及對(duì)象所有的對(duì)象屬性都實(shí)現(xiàn)序列化]
public Outer myclone() {
Outer outer = null;
try { // 將該對(duì)象序列化成流,因?yàn)閷懺诹骼锏氖菍?duì)象的一個(gè)拷貝圈膏,而原對(duì)象仍然存在于JVM里面。所以利用這個(gè)特性可以實(shí)現(xiàn)對(duì)象的深拷貝
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
// 將流序列化成對(duì)象
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
outer = (Outer) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return outer;
}
}
public class Inner implements Serializable{
private static final long serialVersionUID = 872390113109L; //最好是顯式聲明ID
public String name = "";
public Inner(String name) {
this.name = name;
}
@Override
public String toString() {
return "Inner的name值為:" + name;
}
}
注意:基于序列化和反序列化實(shí)現(xiàn)的克隆不僅僅是深度克隆篙骡,更重要的是通過泛型限定稽坤,
可以檢查出要克隆的對(duì)象是否支持序列化,這項(xiàng)檢查是編譯器完成的糯俗,
不是在運(yùn)行時(shí)拋出異常尿褪,這種是方案明顯優(yōu)于使用Object類的clone方法克隆對(duì)象。
讓問題在編譯的時(shí)候暴露出來總是優(yōu)于把問題留到運(yùn)行時(shí)