Clone

java的克隆
/** 
 * 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

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