java中的clone技術

 編程過程中常常遇到如下情況: 假設有一個對象obj1,在某處需要和obj1一樣的實例obj2,強調obj1和obj2是兩個獨立的實例,只是在開始的時候,它們具有一樣的屬性。這種情況下,一般的一種解決方法是:重新new一個對象obj2,然後將obj1的屬性字段值依次賦予obj2。該種方法可行,但是也比較土。java提供了clone方法,使用clone方法,我們可以高效地解決上述的問題。

       在理解clone方法前,有必要先了解下淺拷貝(shallow copy)和深拷貝(deep copy)。先看一個與淺拷貝相關的代碼段:

public class FamilyInfo {
	public String address;
	public int memberNum;
	
	public FamilyInfo(String address, int memberNum) {
		super();
		this.address = address;
		this.memberNum = memberNum;
	}
}

public class Employee {
	public String name;
	public FamilyInfo familyInfo;
	
	public Employee(String name, FamilyInfo familyInfo) {
		super();
		this.name = name;
		this.familyInfo = familyInfo;
	}
}

public class CloneTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		FamilyInfo familyInfoA=new FamilyInfo("No.1100 Lianhang Rd.",2);
		Employee employeeA=new Employee("Lily",familyInfoA);
		System.out.println("employeeA's address "+employeeA.familyInfo.address);
		Employee employeeB=employeeA;
		System.out.println("employeeB's address "+employeeB.familyInfo.address);
		System.out.println("---------------------");
		employeeA.familyInfo.address="No.1588 Pulian Rd.";
		System.out.println("employeeA's address "+employeeA.familyInfo.address);
		System.out.println("employeeB's address "+employeeB.familyInfo.address);	

	}
}

輸出結果爲:

        我們可以看到,隨着employeeA對象 familyInfo值的改變,employeeB對象的值也受到影響。產生這種現象的原因是java中

Employee employeeB=employeeA;這條語句實際上是直接將對象employeeA的引用賦予employeeB,這樣兩個引用指向的是同一個對象。因此,當emploA對象改變的時候,employeeB的值也改變了。這就是淺拷貝。淺拷貝只拷貝對象引用本身,而不去拷貝引用的成員屬性。從這個層次上來說,深clone並不是特別困難,簡單地說,就是創建好對象,再設置一些成員屬性。

       接下來看看java的clone技術是怎麼實現深淺拷貝的。

     java中跟克隆有關的兩個類分別是Cloneable接口和Object類中的clone方法,通過兩者的協作來實現克隆。首先看一下java api doc中關於Cloneable接口和Object類中的clone方法的描述:

                      java.lang.Cloneable 接口,

          此類實現了 Cloneable 接口,以指示 Object.clone() 方法可以合法地對該類實例進行按字段複製。如果在沒有實現 Cloneable 接口的實例上調用 Object 的 clone 方法,則會導致拋出 CloneNotSupportedException異常。 按照慣例,實現此接口的類應該使用公共方法重寫 Object.clone(它是受保護的)。請參閱 Object.clone(),以獲得有關重寫此方法的詳細信息。 

       Cloneable接口沒有任何方法,僅是個標誌接口(tagging interface),若要具有克隆能力,實現Cloneable接口的類必須重寫從Object繼承來的clone方法,並調用Object的clone方法,重寫後的方法應爲public 的。注意的是:java默認的clone()方法是淺拷貝,若要拷貝基本類型外加String類型以外的類型,即聚合或組合類間關係的時候,就需要進行深拷貝了。此時,常用的解決方法是縱深clone,即克隆到基本類型,外加String類型以外,不能再克隆爲止。如下述例子:

public class FamilyInfo implements Cloneable{
	public String address;
	public int memberNum;
	
	public FamilyInfo(String address, int memberNum) {
		super();
		this.address = address;
		this.memberNum = memberNum;
	}
	
	public FamilyInfo clone(){
		FamilyInfo familyInfo=null;
		try {
			familyInfo=(FamilyInfo) super.clone();
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return familyInfo;
	}
}
public class Employee implements Cloneable{
	public String name;
	public FamilyInfo familyInfo;
	
	public Employee(String name, FamilyInfo familyInfo) {
		super();
		this.name = name;
		this.familyInfo = familyInfo;
	}
	
	public Employee clone(){
		Employee employee=null;
		try {
			employee=(Employee) super.clone();
			if(this.familyInfo!=null){
				employee.familyInfo=this.familyInfo.clone();
			}
		} catch (CloneNotSupportedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return employee;
		
	}
	
}

public class CloneTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		FamilyInfo familyInfoA=new FamilyInfo("No.1100 Lianhang Rd.",2);
		Employee employeeA=new Employee("Lily",familyInfoA);
		System.out.println("employeeA's address "+employeeA.familyInfo.address);
		Employee employeeB=employeeA.clone();
		System.out.println("employeeB's address "+employeeB.familyInfo.address);
		System.out.println("---------------------");
		employeeA.familyInfo.address="No.1588 Pulian Rd.";
		System.out.println("employeeA's address "+employeeA.familyInfo.address);
		System.out.println("employeeB's address "+employeeB.familyInfo.address);	

	}
}

輸出結果爲:


可以看到,深拷貝後,兩個對象彼此獨立,不受影響。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章