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

猜你喜欢

转载自blog.csdn.net/autumn03/article/details/80789302