深拷贝和浅拷贝到底有什么区别?

1. Object clone()

在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
}

从上面的代码测试结果来看,拷贝出来的对象与被拷贝对象是完全不同的对象,这样就实现了深拷贝。

总结

浅拷贝只是拷贝了引用类型属性的地址,而深拷贝拷贝了引用类型属性的数据,实现了完全拷贝。

你可能感兴趣的:(Java学习笔记,java,jvm,开发语言)