Javaのディープコピーとシャローコピーについて

1. コピーの紹介

1.1 参照コピー

オブジェクトを指す参照変数のコピーを作成する

Teacher teacher = new Teacher("Taylor",26);
Teacher otherteacher = teacher;
System.out.println(teacher);
System.out.println(otherteacher);

出力:

blog.Teacher@355da254
blog.Teacher@355da254

アドレス値が同じであることが出力結果からわかるため、同じオブジェクトである必要があります。teacher と otherteacher は単なる参照であり、すべて同じオブジェクト Teacher("Taylor", 26) を指しています。これは参照によるコピーと呼ばれます。
ここに画像の説明を挿入

1.2 オブジェクトのコピー

オブジェクト自体のコピーを作成します。

Teacher teacher = new Teacher("Swift",26);
Teacher otherteacher = (Teacher)teacher.clone();
System.out.println(teacher);
System.out.println(otherteacher);

出力:

blog.Teacher@355da254
blog.Teacher@4dc63996

出力結果から、それらのアドレスが異なることがわかります。つまり、元のオブジェクトのアドレスを新しい参照変数に代入する代わりに、新しいオブジェクトが作成されます。これをオブジェクトのコピーと呼びます
ここに画像の説明を挿入

2.ディープコピーとシャローコピー

Java言語では、オブジェクトをコピーする必要がある場合、浅いコピーと深いコピーの2種類のコピーがあります。
浅いコピーはコピー元オブジェクトのアドレスのみをコピーするため、コピー元オブジェクトの値が変わると、コピーされたオブジェクトの値も変わります。
ディープコピーはソース オブジェクトの値をすべてコピーするため、ソース オブジェクトの値が変更されても、コピーされたオブジェクトの値は変更されません。下の図に示すように:
ここに画像の説明を挿入

2.1 浅いコピー

定義:
コピーされたオブジェクトのすべての変数は、元のオブジェクトと同じ値を含み、他のオブジェクトへのすべての参照は依然として元のオブジェクトを指しています。つまり、オブジェクトの浅いコピーは「メイン」オブジェクトのコピーを作成しますが、メイン オブジェクト内のオブジェクトはコピーしません。「内部のオブジェクト」は、元のオブジェクトとそのコピーの間で共有されます。

要するに、浅いコピーは問題のオブジェクトのみをコピーし、それが参照するオブジェクトはコピーしません。

浅いコピーの例:

public class ShallowCopy {
    
    
    public static void main(String[] args) throws CloneNotSupportedException {
    
    
        Teacher teacher = new Teacher();
        teacher.setName("Delacey");
        teacher.setAge(29);

        Student2 student1 = new Student2();
        student1.setName("Dream");
        student1.setAge(18);
        student1.setTeacher(teacher);

        Student2 student2 = (Student2) student1.clone();//拷贝
        System.out.println("拷贝后");
        System.out.println(student2.getName());
        System.out.println(student2.getAge());
        System.out.println(student2.getTeacher().getName());
        System.out.println(student2.getTeacher().getAge());
        System.out.println("修改老师的信息后-------------");

        // 修改老师的信息
        teacher.setName("Jam");
        System.out.println(student1.getTeacher().getName());
        System.out.println(student2.getTeacher().getName());
    }

}

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

class Student2 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
    public Object clone() throws CloneNotSupportedException {
    
    
        Object object = super.clone();
        return object;
    }

}

出力

拷贝后
Dream
18
Delacey
29
修改老师的信息后-------------
Jam
Jam

結果分析: 2 つの参照 Student1 と Student2 は 2 つの異なるオブジェクトを指していますが、2 つの参照 Student1 と Student2 内の 2 つの Teacher 参照は同じオブジェクトを指しているため、浅いコピーです
ここに画像の説明を挿入

2.2 ディープコピー

定義:
ディープ コピーは、独立したオブジェクト全体のコピーです. ディープ コピーは、すべての属性をコピーし、属性が指す動的に割り当てられたメモリをコピーします. ディープ コピーは、オブジェクトが参照先のオブジェクトと共にコピーされるときに発生します。ディープ コピーは、シャロー コピーよりも遅く、コストが高くなります。

つまり、ディープ コピーは、コピー対象のオブジェクトが参照するすべてのオブジェクトをコピーします。

ディープ コピー インスタンス 1 を実装します。

public class DeepCopy {
    
    
    public static void main(String[] args) throws Exception {
    
    
        Teacher2 teacher = new Teacher2();
        teacher.setName("Delacey");
        teacher.setAge(29);

        Student3 student1 = new Student3();
        student1.setName("Dream");
        student1.setAge(18);
        student1.setTeacher(teacher);

        Student3 student2 = (Student3) student1.clone();//拷贝
        System.out.println("拷贝后");
        System.out.println(student2.getName());
        System.out.println(student2.getAge());
        System.out.println(student2.getTeacher().getName());
        System.out.println(student2.getTeacher().getAge());
        System.out.println("修改老师的信息后-------------");

        // 修改老师的信息
        teacher.setName("Jam");
        System.out.println(student1.getTeacher().getName());
        System.out.println(student2.getTeacher().getName());
    }
}

class Teacher2 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
    public Object clone() throws CloneNotSupportedException {
    
    
        return super.clone();
    }

}

class Student3 implements Cloneable {
    
    
    private String name;
    private int age;
    private Teacher2 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 Teacher2 getTeacher() {
    
    
        return teacher;
    }

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

    @Override
    public Object clone() throws CloneNotSupportedException {
    
    
        // 浅复制时:
        // Object object = super.clone();
        // return object;

        // 改为深复制:
        Student3 student = (Student3) super.clone();
        // 本来是浅复制,现在将Teacher对象复制一份并重新set进来
        student.setTeacher((Teacher2) student.getTeacher().clone());
        return student;
    }

}


出力結果:

拷贝后
Dream
18
Delacey
29
修改老师的信息后-------------
Jam
Delacey

結果分析:
2 つの参照学生 1 と学生 2 は 2 つの異なるオブジェクトを指し、2 つの参照学生 1 と学生 2 の 2 つの教師参照は 2 つのオブジェクトを指しますが、教師オブジェクトの変更は学生 1 オブジェクトにのみ影響を与える可能性があるため、深いです。コピー。

下の図は、変更前の先生の名前 Delacey を示しています:
ここに画像の説明を挿入
下の図は、先生の名前を示しています Jam の変更:
ここに画像の説明を挿入
シリアライゼーションを使用してディープコピーを実現しています:

public class DeepCopyServiable {
    
    
    public static void main(String[] args) throws Exception {
    
    
        Teacher3 t = new Teacher3();
        t.setName("Taylor");
        t.setAge(28);

        Student3 s1 = new Student3();
        s1.setAge(20);
        s1.setName("blank space");
        s1.setTeacher(t);

        Student3 s2 = (Student3) s1.deepClone();//拷贝

        System.out.println("拷贝后:");
        System.out.println(s2.getName());
        System.out.println(s2.getAge());
        System.out.println(s2.getTeacher().getName());
        System.out.println(s2.getTeacher().getAge());
        System.out.println("---------------------------");

        t.setName("swift");

        System.out.println("修改后:");
        System.out.println(s1.getTeacher().getName());
        System.out.println(s2.getTeacher().getName());
    }
}

class Teacher3 implements Serializable {
    
    
    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;
    }

}

class Student3 implements Serializable {
    
    
    private String name;
    private int age;
    private Teacher3 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 Teacher3 getTeacher() {
    
    
        return teacher;
    }

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

    public Object deepClone() throws Exception {
    
    
        // 序列化
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);

        oos.writeObject(this);

        // 反序列化
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);

        return ois.readObject();
    }
}

出力結果

拷贝后:
blank space
20
Taylor
28
---------------------------
修改后:
swift
Taylor

結果分析:シリアル化によりオブジェクトのディープコピーが実現されていることがわかる

参考ブログ記事(侵入・削除):
https://blog.csdn.net/baiye_xing/article/details/71788741
https://www.cnblogs.com/ysocean/p/8482979.html
https://www.cnblogs .com/xinruyi/p/11537963.html

おすすめ

転載: blog.csdn.net/mfysss/article/details/129116659