1. 程式人生 > 其它 >深入理解Java淺拷貝和深拷貝

深入理解Java淺拷貝和深拷貝

首先說一下什麼是引用拷貝和物件拷貝。

1. 引用拷貝:

​ 引用拷貝就是建立一個指向物件的引用變數的拷貝,拷貝後生成的物件和原來的物件仍是一個物件,也就是說他們在記憶體空間中的地址是一樣的。

2. 物件拷貝

​ 物件拷貝就是建立物件本身的一個副本,就是在記憶體空間中開闢一個新的區域存放該物件,這時候就是兩個物件了!

深拷貝和淺拷貝都是物件拷貝

1.淺拷貝

​ 被複制物件的所有變數都含有與原來的物件相同的值,而所有的對其他物件的引用仍然指向原來的物件。即物件的淺拷貝會對“主”物件進行拷貝,但不會複製主物件裡面的物件。”裡面的物件“會在原來的物件和它的副本之間共享。

簡單來說就是隻拷貝你考慮的物件,對於內部物件和原來的物件共享。

下面結合程式碼來看看:

//教師類,是學生類的內部物件
//實現Cloneable介面,預設實現的是淺拷貝
public class Teacher implements Cloneable {
    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;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

//學生類,也是我們要拷貝的“主類”
public class Student implements Cloneable {
    private String name;
    private int age;
    private Teacher teacher;

    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 Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

 
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    } 
}

測試類:

public class shallowCopy {
    public static void main(String[] args) throws CloneNotSupportedException {
        Teacher teacher = new Teacher();
        teacher.setName("liumei");
        teacher.setAge(25);

        Student student1 = new Student();
        student1.setName("mike");
        student1.setAge(18);
        student1.setTeacher(teacher);

        Student student2 = (Student) student1.clone();

        //student
        System.out.println(student1);
        System.out.println(student2);
        
        //teacher
        System.out.println(student1.getTeacher());
        System.out.println(student2.getTeacher());

    }
}

測試結果:

從結果中可以看出,student1和student2是兩個物件,而兩個學生物件的teacher物件地址卻是相同的,這也就印證了我們上邊的結論,淺拷貝是不拷貝內部引用的物件的!

2. 深拷貝

​ 深拷貝是一個整個獨立的物件拷貝,深拷貝會拷貝所有的屬性,並拷貝屬性指向的動態分配的記憶體。當物件和它所引用的物件一起拷貝時即發生深拷貝。深拷貝相比於淺拷貝速度較慢並且花銷較大。

簡而言之,深拷貝把要複製的物件和引用的物件都複製了一遍。

下面結合程式碼來看看:

教師類和上述程式碼一致,我們只看學生類。

public class Student implements Cloneable {
    private String name;
    private int age;
    private Teacher teacher;

    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 Teacher getTeacher() {
        return teacher;
    }

    public void setTeacher(Teacher teacher) {
        this.teacher = teacher;
    }

 

    /**
     * 深拷貝:不僅賦值主物件,還將內部的物件也重新複製一份
     * @return
     * @throws CloneNotSupportedException
     */
    @Override
    protected Object clone() throws CloneNotSupportedException {
        //拷貝student物件
        Student student = (Student) super.clone();
        //拷貝teacher物件,並將其放入拷貝後生成的student物件中
        student.setTeacher((Teacher) teacher.clone());
        return student;
    }
}

測試類與淺拷貝一致,我們直接看結果:

誒? 這次不僅兩個學生類的地址不一樣了,連內部的teacher類物件的地址也不相同了!

也就是說 深拷貝確實是將內部的引用物件也重新為它開闢空間!

下面看看淺拷貝和深拷貝在記憶體空間中的圖解應該就更能理解了。

淺拷貝

深拷貝