前言
clone是Object类的一个本地方法,Object类默认使用的是浅拷贝,如果想要实现深拷贝,需要去实现Cloneable接口,并重写clone方法。
浅拷贝是指:当对象的属性是基本数据类型时,会复制属性及值,当对象的属性有引用类型的时候,会把当前属性引用复制。
深拷贝是指:当对象的属性是基本数据类型时,会复制属性及值,当对象的属性有引用类型的时候,会把当前属性引用的对象再复制一份。
区别就是:当需要clone的对象的属性都是基本数据类型,深拷贝浅拷贝一样,当需要clone的对象的属性有引用类型的时候,浅拷贝直接把引用地址复制过去,深拷贝会把引用的对象再复制一份。
下面是例子:
浅拷贝
public class Test{
public static void main(String[] args) throws CloneNotSupportedException{
Professor p1=new Professor();
p1.setName("zhang");
p1.setAge(44);
Student s1=new Student();
s1.setName("Xiao Ming");
s1.setAge(15);
s1.setProfessor(p1);
System.out.println(s1);
Student s2=(Student) s1.clone();//克隆s1
Professor p2=s2.getProfessor();//这里其实获取的是p1的引用
//其实这里修改的也是p1的属性
p2.setName("Li");
p2.setAage(55);
s2.setProfessor(p2);
s2.setAge(88);//这里是基本数据类型
s2.setName("Wu");//这里是基本数据类型
System.out.println("修改前 :"+s1);
System.out.println("修改后 :"+s2);
}
}
class Student implements{
private String name;
private int age;
private Professor professor;
....set、get方法
...toString方法
@Override
protected Object clone()throws CloneNotSupportedException{
return super.clone();
}
}
class Professor {
private String name;
private int age;
...set、get方法
...toString方法
}
发现问题,当修改p2的时候,p1也跟着变了,是因为p1和p2指向的是同一个对象,所以clone的是引用。
深拷贝
public class Test{
public static void main(String[] args) throws CloneNotSupportedException{
Professor p1=new Professor();
p1.setName("zhang");
p1.setAge(44);
Student s1=new Student();
s1.setName("Xiao Ming");
s1.setAge(15);
s1.setProfessor(p1);
System.out.println(s1);
Student s2=(Student) s1.clone();//克隆s1
Professor p2=s2.getProfessor();//这里其实获取的是p1的引用
//其实这里修改的也是p1的属性
p2.setName("Li");
p2.setAage(55);
s2.setProfessor(p2);
s2.setAge(88);//这里是基本数据类型
s2.setName("Wu");//这里是基本数据类型
System.out.println("修改前 :"+s1);
System.out.println("修改后 :"+s2);
}
}
class Student implements{
private String name;
private int age;
private Professor professor;
....set、get方法
...toString方法
@Override
protected Object clone()throws CloneNotSupportedException{
Student newStudent=(Student) super.clone();
newStudent.professor=(Professor) professor.clone();
return newStudent;
}
}
class Professor implements Cloneable {
private String name;
private int age;
...set、get方法
...toString方法
@Override
protected Object clone()throws CloneNotSupportedException{
return super.clone();
}
}
这一次发现修改s2的引用类型后,并没有对s1产生影响了。其实深拷贝也就是把所有的引用的对象属性再做一个clone,直到最终的所有的属性都是基本数据类型。
补充
发现了一种深拷贝的新的方法,使用序列化,把需要进行深拷贝的实体类都实现Serializable后,拷贝时将当前对象写入流内,然后再读出来,这样也可以实现深拷贝。这个代码比较简单,就不再贴上来了。