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