2種方法實現java對象的深拷貝
版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
1、如果一個類沒有實現Cloneable接口,直接調用clone()方法,會報異常CloneNotSupportedException,這一點已經在Object源碼中寫道:
-
* @return a clone of this instance.
-
* @exception CloneNotSupportedException if the object's class does not
-
* support the {@code Cloneable} interface. Subclasses
-
* that override the {@code clone} method can also
-
* throw this exception to indicate that an instance cannot
-
* be cloned.
-
* @see java.lang.Cloneable
-
*/
-
protected native Object clone() throws CloneNotSupportedException;
而且,源碼也寫到Object的clone()方法是淺拷貝的,這一點在之前的Object源碼分析中我已經寫過了.
2、自定義類實現深拷貝方法有2種,下面依次給出具體寫法。
2.1、自定義類要實現Cloneable接口,並覆寫clone()方法。
-
/**
-
* 深拷貝和淺拷貝的測試
-
*/
-
//測試類1
-
class Person implements Cloneable{
-
String name;
-
int age;
-
Person(String name, int age){
-
this.name=name;
-
this.age=age;
-
}
-
-
public Object clone() {
-
try{
-
return super.clone();
-
} catch(CloneNotSupportedException e){
-
return null;
-
}
-
}
-
}
-
//測試類2
-
-
class Animal implements Cloneable{
-
Person host; //主人
-
int age;//年紀
-
Animal(Person person, int age){
-
this.host=person;
-
this.age=age;
-
}
-
-
public Object clone(){
-
try{
-
Animal animal=(Animal) super.clone();
-
animal.host=(Person)host.clone(); //深拷貝處理
-
return animal;
-
} catch (CloneNotSupportedException e){
-
return null;
-
}
-
}
-
}
-
-
//測試
-
public class Main{
-
public static void main(String[] args) {
-
Person person1= new Person("cxh",26);
-
Person person2=(Person)person1.clone();
-
System.out.println( "----------------淺拷貝--------------");
-
//測試Object的clone方法為淺拷貝
-
//String類用==測試內存地址是否一致
-
System.out.println( "person1和person2的name內存地址是否相同:"+(person1.name==person2.name));
-
-
-
-
System.out.println( "----------------深拷貝--------------");
-
//重寫Object的clone方法,實現深拷貝
-
//還是用==查看兩個對象的內存地址是否相等來確定是否為兩個對象,如果是兩個內存地址,那么就是深拷貝
-
Animal animal1= new Animal(new Person("cxh",26),3);
-
Animal animal2=(Animal) animal1.clone();
-
System.out.println( "animal1和animal2的host內存地址是否相同:"+(animal1.host==animal2.host));
-
}
-
}
輸出:
-
----------------淺拷貝--------------
-
person1和person2的name內存地址是否相同: true
-
----------------深拷貝--------------
-
animal1和animal2的host內存地址是否相同: false
-
-
Process finished with exit code 0
一個講解很詳細的博客:http://blog.csdn.net/zhangjg_blog/article/details/18369201
2.2、通過序列化方式實現深拷貝:先將要拷貝對象寫入到內存中的字節流中,然后再從這個字節流中讀出剛剛存儲的信息,作為一個新對象返回,那么這個新對象和原對象就不存在任何地址上的共享,自然實現了深拷貝。
自定義類需要實現Serializable接口。
-
import java.io.*;
-
-
/**
-
* 深拷貝和淺拷貝的測試
-
* 如何利用序列化來完成對象的拷貝呢?在內存中通過字節流的拷貝是比較容易實現的。把母對象寫入到一個字節流中,再從字節流中將其讀出來,
-
* 這樣就可以創建一個新的對象了,並且該新對象與母對象之間並不存在引用共享的問題,真正實現對象的深拷貝。
-
*/
-
//工具類
-
class CloneUtil{
-
public static <T extends Serializable> T clone(T obj){
-
T cloneObj= null;
-
try{
-
//寫入字節流
-
ByteArrayOutputStream baos= new ByteArrayOutputStream();
-
ObjectOutputStream oos= new ObjectOutputStream(baos);
-
oos.writeObject(obj);
-
oos.close();
-
-
//分配內存,寫入原始對象,生成新對象
-
ByteArrayInputStream bais= new ByteArrayInputStream(baos.toByteArray());//獲取上面的輸出字節流
-
ObjectInputStream ois= new ObjectInputStream(bais);
-
-
//返回生成的新對象
-
cloneObj=(T)ois.readObject();
-
ois.close();
-
} catch (Exception e){
-
e.printStackTrace();
-
}
-
return cloneObj;
-
}
-
}
-
-
//測試類1
-
class Person implements Serializable{
-
String name;
-
int age;
-
Person(String name, int age){
-
this.name=name;
-
this.age=age;
-
}
-
-
}
-
//測試類2
-
-
class Animal implements Serializable{
-
Person host; //主人
-
int age;//年紀
-
Animal(Person person, int age){
-
this.host=person;
-
this.age=age;
-
}
-
}
-
-
-
//測試
-
public class Main{
-
public static void main(String[] args) {
-
System.out.println( "----------------深拷貝--------------");
-
//重寫Object的clone方法,實現深拷貝
-
//還是用==查看兩個對象的內存地址是否相等來確定是否為兩個對象,如果是兩個內存地址,那么就是深拷貝
-
Animal animal1= new Animal(new Person("cxh",26),3);
-
Animal animal2=CloneUtil.clone(animal1);
-
System.out.println( "animal1和animal2的host內存地址是否相同:"+(animal1.host==animal2.host));
-
}
-
}
輸出結果:
-
----------------深拷貝--------------
-
animal1和animal2的host內存地址是否相同: false
參考博客: http://blog.csdn.net/chenssy/article/details/12952063