前言:
protected native Object clone() throws CloneNotSupportedException方法由protected修饰,只能由子类重写和调用,而且为本地方法。
Object提供clone方法,生成对象的一个副本,来实现对象的一次浅度克隆。但是对象的引用类型不会拷贝一份,引用地址与原对象相同。
实现对象的克隆需要实现Cloneable接口,重写clone方法,通过super.clone()调用Object类的clone方法得到当前对象的副本,并放回该副本。
浅度克隆与深度克隆的区别:
浅度克隆:基本类型都会拷贝一份,引用类型引用地址不变,还是同一个对象。
深度克隆:基本类型和引用类型都会拷贝一份,完完全全的是不同的两份,引用地址不一样。
下面结合一个具体的例子:(两者结合)
定义person类:(实现了Cloneable接口)
class Person implements Cloneable{
int id;
public Person(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
定义Student类(实现Cloneable接口)
public class Student implements Cloneable{
private int age; //基本类型
private String name; //引用类型,未实现自己的深度拷贝
private Person person; //引用类型,Person类实现了Cloneable接口,深度拷贝
public Student(int age, String name, Person person) {
this.age = age;
this.name = name;
this.person = person;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Student student = (Student) super.clone();
Person person = (Person) student.getPerson().clone(); //这个为重点,把student里面的引用类型person深度克隆
student.setPerson(person);
return student;
}
public static void main(String[] args) throws Exception{
Person person = new Person(2);
Student student1 = new Student(10,"wqh", person);
Student student2 = (Student) student1.clone();
System.out.println(student1 == student2); //false
System.out.println(student1.getName()==student2.getName()); //true
System.out.println(student1.getPerson() == student2.getPerson()); //false
}
}
输出结果:
false
true
false
分析:
Student中有两个引用类型:String和Person,在Person中实现了clone接口,在Student的clone方法中我们对person属性也进行了一次深度克隆,这样对student1拷贝成student2后,各自的person属性是单独的两份,引用地址不一样,所以为false,但是string属性是同一份,故为true。综述,对student2而言,这是一次不彻底的深度克隆,因为部分引用属性没有进行深度克隆。
画个图来明了下:
student1和student2对应于堆中的同一个name,不同的person。