在Java语言中,所有对象的父类Object有一个clone()方法,但是new出来的对象不能调用它。如何来让对象可以调用该方法呢? 答案是重写Object的clone()方法并实现Cloneable接口。
public class Student implements Cloneable{
private String name;
private int age;
private Cat cat;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
……省略属性的getter、setter方法
}
按照上面的方法实现的类已经可以调用clone(),接下来我们就可以探究深拷贝和浅拷贝的区别了。
浅拷贝简单来说,浅拷贝相对于new了一个新的,新对象和旧对象的非引用数据类型的属性值相同,两者这类属性的修改互不影响。但是新对象和旧对象的引用类型属性引用地址是相同的,相对于对于引用类型复制了地址,实际上,引用的还是同一个对象,修改引用类型的属性值另一个对象也会改变。
下面是一个student类,有三个属性,两个非引用类型,一个cat属性为引用类型。
public class Student implements Cloneable{
private String name;
private int age;
private Cat cat;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
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 class Cat {
private String name;
private int age;
public Cat(String name, int age) {
this.name = name;
this.age = 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 static void main(String[] args) throws CloneNotSupportedException {
Student student = new Student("xiaoming", 17);
Cat cat = new Cat("huahua", 6);
student.setCat(cat);
Student studentC = (Student)student.clone();
System.out.println(studentC == student); // false
System.out.println(studentC.getCat() == student.getCat()); // true
}
上述代码执行的结果为false和true,第二个结果为true,说明这两个对象的cat属性地址是相同的,这就是浅拷贝。
深拷贝其实是浅拷贝的完善,要实现深拷贝要求对象进行clone时,对于引用类型对象,调用其自身的clone方法进行克隆,这样拷贝出来的对象,就是完全不同的对象,两者不会相互影响。
下面的代码中,Person有三个属性,其中Dog为引用类型,person和dog都实现了Cloneable接口并重写了clone方法,注意,person中的clone方法中调用了dog的clone方法。
public class Person implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException {
Person clone = (Person) super.clone();
clone.dog = (Dog) dog.clone();
return clone;
}
private String name;
private int age;
private Dog dog;
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Person(String name, int age) {
this.name = name;
this.age = 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 class Dog implements Cloneable{
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = 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;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person("yewenjie", 40);
Dog dog = new Dog("panghu", 2);
person.setDog(dog);
Person personC = (Person) person.clone();
System.out.println(person == personC); //false
System.out.println(person.getDog() == personC.getDog()); // false
}
从上面的代码测试结果来看,拷贝出来的对象与被拷贝对象是完全不同的对象,这样就实现了深拷贝。
浅拷贝只是拷贝了引用类型属性的地址,而深拷贝拷贝了引用类型属性的数据,实现了完全拷贝。