Java的clone()方法,淺複製與深複製

要想實現克隆,需要實現Cloneable接口並重寫clone()方法。

淺複製,對於基本類型也會重新new一個空間來存儲,而對於一個類中關聯的其他類則會指複製指向那個對象的引用。例如。

public class Student {
	private int age = 0;

	public Student(int age) {
		super();
		this.age = age;
	}

	public int getAge() {
		return this.age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	
}

 

public class Test implements Cloneable {
	private int i;
	private Student student=new Student(0);
	public int getI() {
		return i;
	}

	public void setI(int i) {
		this.i = i;
	}

	public Student getStudent() {
		return student;
	}

	public void setStudent(Student student) {
		this.student = student;
	}

	public Object clone() {
		Test cloneTest = null;
		try {
			cloneTest = (Test) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return cloneTest;
	}

	public void testClone() {
		Test t = (Test) clone();
		t.setI(2);
		System.out.println("int i: " + t.getI());
		t.getStudent().setAge(20);
		System.out.println("age:" + t.getStudent().getAge());
	}
	public static void main(String[] agrs) throws Exception {
		Test test = new Test();
		System.out.println(" clone...");
		test.testClone();
		System.out.println("the origal value...");
		System.out.println("int i: " + test.getI());
		System.out.println("age: " + test.getStudent().getAge());
}

 

會輸出:

clone...
int i: 2
age:20
the origal value...
int i: 0
age: 20

 

可以看到我修改克隆後的Student的對象,使原來的Student對象受到影響,可知複製的是引用,而非真正的一個對象。

還有就是,int i 的值的確變了,因爲是基本類型,clone的時候會簡單的new 出一個空間存新的i的值。

下面看用深複製來處理:

重寫Student類的clone方法,雖然Student類只有簡單類型的屬性,這樣做其他類調用Student對象的clone()方法實現克隆,而不是 其他類.setStudent(new Student(0))的方式,前種方式對日後擴展比較好,因爲只需要在Studnet類裏的clone方法加代碼,而不需要修改用到Student對象的類。

public class Student implements Cloneable{
	private int age = 0;

	public Student(int age) {
		super();
		this.age = age;
	}

	public int getAge() {
		return this.age;
	}

	public void setAge(int age) {
		this.age = age;
	}
	public Object clone() {
		Student cloneStudent = null;
		try {
			
			cloneStudent = (Student) super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return cloneStudent;
	}
}
 

修改Test類下的clone()方法:

	public Object clone() {
		Test cloneTest = null;
		try {
			cloneTest = (Test) super.clone();
                        cloneTest.setStudent((Student)student.clone());
                      //cloneTest.setStudent(new Student(0));這樣不需要重寫Student類裏的clone方法,
                     //因爲其只有基本類型的屬性。
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return cloneTest;
	}

 再次運行後的結果爲:

clone...
int i: 2
age:20
the origal value...
int i: 0
age: 0

Test對象clone()後,再對其student對象進行修改不會影響原始Test對象的值,因爲此克隆後的Test對象在堆中已經開闢一個區域用於存儲Student對象,而不是它的引用。

 

關聯知識:

Test類中重寫的clone()方法中調用了super.clone(),是因爲無論clone類的繼承結構是什麼樣的,super.clone()都會調用java.lang.Object類的clone()方法。Object類的clone()一個native方法,native方法的效率一般來說都是遠高於java中的非native方法。

 

還有一點要考慮的是爲了讓其它類能調用這個clone類的clone()方法,重載之後要把clone()方法的屬性設置爲public。

 

 

發佈了129 篇原創文章 · 獲贊 3 · 訪問量 8573
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章