/** * Creates and returns a copy of this {@code Object}. The default * implementation returns a so-called "shallow" copy: It creates a new * instance of the same class and then copies the field values (including * object references) from this instance to the new instance. A "deep" copy, * in contrast, would also recursively clone nested objects. A subclass that * needs to implement this kind of cloning should call {@code super.clone()} * to create the new instance and then create deep copies of the nested, * mutable objects. * * @return a copy of this object. * @throws CloneNotSupportedException * if this object's class does not implement the {@code * Cloneable} interface. */ protected Object clone() throws CloneNotSupportedException { if (!(this instanceof Cloneable)) { throw new CloneNotSupportedException("Class doesn't implement Cloneable"); } return internalClone((Cloneable) this); } /* * Native helper method for cloning. */ private native Object internalClone(Cloneable o);
clone方法首先會判斷對象是否實現了Cloneable接口,若無則拋出CloneNotSupportedException,最後調用internalClone.intervalClone是一個native方法,一般來說native方法的執行效率高於非native方法。
當某個類要複寫clone方法時,要實現Cloneable接口,通常的克隆對象都是通過super.clone()來實現。
例子:首先建立一個Student類
package CloneTest;
public class Student implements Cloneable{
private String name;
private int age;
private Professor professor;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Professor getProfessor() {
return professor;
}
public void setProfessor(Professor professor) {
this.professor = professor;
}
public String toString(){
return "Student [name="+name+", age="+age+",professor="+professor+"]";
}
public Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
再建立Professor類
package CloneTest;
public class Professor {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String toString(){
return "Professor [name=" +name+ ",age=" +age+ "]";
}
}
package CloneTest;
public class ShadowCopy {
public static void main(String[] args) {
// TODO Auto-generated method stub
Professor p1=new Professor();
p1.setName("Professor Zhang");
p1.setAge(30);
Student s1=new Student();
s1.setName("zhang san");
s1.setAge(20);
s1.setProfessor(p1);
System.out.println(s1);
try{
Student s2=(Student)s1.clone();
Professor p2=s2.getProfessor();
p2.setName("Professor Li");
p2.setAge(45);
s2.setProfessor(p2);
System.out.println("複製後的 s1= "+s1);
System.out.println("複製後的 s2= "+s2);
}catch(Exception e){
e.printStackTrace();
}
}
}
通過將s1進行clone給s2,並將s2的professor進行修改,結果如下
Student [name=zhang san, age=20,professor=Professor [name=Professor Zhang,age=30]]
複製後的 s1= Student [name=zhang san, age=20,professor=Professor [name=Professor Li,age=45]]
複製後的 s2= Student [name=zhang san, age=20,professor=Professor [name=Professor Li,age=45]]
發現,s1和s2的professor信息都進行了修改
將測試代碼ShadowCopy進行修改,對複製後S2的name和age也進行修改,即
package CloneTest;
public class ShadowCopy {
public static void main(String[] args) {
// TODO Auto-generated method stub
Professor p1=new Professor();
p1.setName("Professor Zhang");
p1.setAge(30);
Student s1=new Student();
s1.setName("zhang san");
s1.setAge(20);
s1.setProfessor(p1);
System.out.println(s1);
try{
Student s2=(Student)s1.clone();
s2.setName("li si");
s2.setAge(18);
Professor p2=s2.getProfessor();
p2.setName("Professor Li");
p2.setAge(45);
s2.setProfessor(p2);
System.out.println("複製後的 s1= "+s1);
System.out.println("複製後的 s2= "+s2);
}catch(Exception e){
e.printStackTrace();
}
}
}
Student [name=zhang san, age=20,professor=Professor [name=Professor Zhang,age=30]]
複製後的 s1= Student [name=zhang san, age=20,professor=Professor [name=Professor Li,age=45]]
複製後的 s2= Student [name=li si, age=18,professor=Professor [name=Professor Li,age=45]]
so,Student的字段如果不是一個引用時,修改clone得到對象的該字段(name,age)並不會影響原來的對象,但是當字段爲一個引用時,修改clone得到對象的該字段(professor)時會影響原來的對象。這即淺複製。
so,要進行深複製,首先讓Professor實現Cloneable接口,並複寫Student類中的clone方法,如下:
public Object clone() throws CloneNotSupportedException{
Student newStudent=new Student();
newStudent.professor=(Professor)professor.clone();
return newStudent;
}
Student [name=zhang san, age=20,professor=Professor [name=Professor Zhang,age=30]]
複製後的 s1= Student [name=zhang san, age=20,professor=Professor [name=Professor Zhang,age=30]]
複製後的 s2= Student [name=li si, age=18,professor=Professor [name=Professor Li,age=45]]
由此可見,修改clone()得到的s2的任何字段都不會影響s1的字段,這就是深複製的作用。
參考:https://www.cnblogs.com/acode/p/6306887.html