要想實現克隆,需要實現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。