Java deep copy and shallow copy concept and code implementation

copy concept

Regarding copying, in simple terms, it creates an object that is exactly the same as a known object. Copy in Java includes deep copy and shallow copy, which may not be used much in the daily coding process, but this is a question that is often asked in interviews.

What is Java Shallow Copy?

Shallow copy is to copy each property of the object in turn, but when the property value of the object is a reference type, the actual copy is its reference, and when the value pointed to by the reference changes, it will also change.

What is Java deep copy?

Deep copy copies the variable value, and for reference data, it recurses to the basic type before copying. The object after deep copy is completely isolated from the original object and does not affect each other. Modifications to one object will not affect another object.

What is the difference between shallow copy and deep copy in Java?

Generally speaking, a shallow copy copies its reference, and when the value pointed to by the reference changes, it also changes; while a deep copy is completely isolated from the original object and does not affect each other.

Implementation of copy

Shallow copy implementation

First, let's define a simple object that needs to be copied.

We define a Student student class, which contains name, age, sex, but another School class, which contains schoolName school name and stuNums number of students and Student students, where Student is not a string, but a Student class .

school object

package com.yyl.javaprogram.copy;

public class School implements Cloneable {
    private String schoolName;
    private int stuNums;
    private Student stu;

    public String getSchoolName() {
        return schoolName;
    }

    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
    }

    public int getStuNums() {
        return stuNums;
    }

    public void setStuNums(int stuNums) {
        this.stuNums = stuNums;
    }

    public Student getStu() {
        return stu;
    }

    public void setStu(Student stu) {
        this.stu = stu;
    }

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

    @Override
    public String toString() {
        return "School{" +
                "schoolName='" + schoolName + '\'' +
                ", stuNums=" + stuNums +
                ", stu=" + stu +
                '}';
    }
}

Student object:

package com.yyl.javaprogram.copy;

public class Student {
    private String name;
    private int age;
    private String sex;

    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 String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }
}

At this time, we want to assign the original class School. Next we generate a School object and call its clone method to copy a new object.

Note: To call the clone method of an object, the class must implement the Cloneable interface and override the clone method.

package com.yyl.javaprogram.copy;

public class LightCopy {
    public static void main(String[] args) throws CloneNotSupportedException {
        // Create the initial School object
        School s1 = new School();
        s1.setSchoolName("Yanshan University");
        s1.setStuNums(20000);
        Student stu1 = new Student();
        stu1.setAge(18);
        stu1.setName("jade like a dream");
        stu1.setSex("Female");
        s1.setStu(stu1);
        // Call the overridden clone method to clone a new school---s2
        School s2 = (School) s1.clone();
        System.out.println("clone s1 Out of a new school: s2");
        System.out.println("s1: "+s1+" s1 of hashcode:"+s1.hashCode()+" s1 middle stu1 of hashcode:"+s1.getStu().hashCode());
        System.out.println("s2: "+s2+" s2 of hashcode:"+s2.hashCode()+" s2 middle stu1 of hashcode:"+s2.getStu().hashCode());
        //System.out.println(s1.getStu().getAge()==s2.getStu().getAge());
        System.out.println("----------------------------");
        System.out.println("Modify the cloned object");
        Student student2 = s2.getStu();
        student2.setAge(21);
        student2.setName("Qu Huashang");
        s2.setStu(student2);
        s2.setSchoolName("YSU");
        System.out.println("After the modification, the students of the two schools are the same, but the school is not cloned, so s2 Modification does not affect s1");
        System.out.println("s1: "+s1+" s1 of hashcode:"+s1.hashCode()+" s1 middle stu1 of hashcode:"+s1.getStu().hashCode());
        System.out.println("s2: "+s2+" s2 of hashcode:"+s2.hashCode()+" s2 middle stu1 of hashcode:"+s2.getStu().hashCode());
        System.out.println(s1.getStu().getAge()==s2.getStu().getAge());
    }
}

Let's look at the output

Analysis of the results: Here, two representative attribute values ​​are selected for the School class: one is a pass-by-reference type (Student object); the other is a string type (school name: a constant) and a basic data type (age).

A shallow copy is performed through the copy construction method, and each attribute value is successfully copied. Among them, when the attribute value of the value transfer part of p1 changes, p2 will not change; and when the attribute value of the reference transfer part changes, p2 also changes.

The basic data type is transfer by value, so modifying the value will not affect the property value of another object; the reference data type is address transfer (pass by reference), so after modifying the value, the property value of another object will be modified synchronously.

The String type is very special. First of all, the String type is a reference data type, not a basic data type, but the data of the String type is stored in the constant pool, that is, it cannot be modified! That is to say, when the name attribute is changed from "Yanshan University" to "YSU", the value of this data is not modified, but the reference of this data is changed from the constant pointing to "Yanshan University" to "YSU" this constant. In this case, the value of the name attribute of another object still points to "Yanshan University" and will not be affected.

It should be noted that if in the copy construction method, new memory spaces are opened up one by one for the reference data type variables, and new objects are created, deep copying can also be achieved. For the general copy construction, it must be a shallow copy.

Implementation of deep copy

There are many ways to deep copy, this time we introduce three ways

  • Method 1 Constructor
  • Method 2 Overload clone() method
  • Method three Serializable serialization

Method 1: Constructor

public static void constructorCopy() {
    Student student = new Student("Xiao Li", 21, "male");
    School school = new School("xx the University", 100, student);
    // Make a deep copy when calling the constructor
    School copySchool = new School(school.getSchoolName(),
            school.getStuNums(),
            new Student(student.getName(),
            student.getAge(),
            student.getSex()));
    // Modify the value of the source object
    copySchool.getStudent().setSex("Female");
    // Check two objects have different values
    System.out.println(school.hashCode() == copySchool.hashCode());
}

The result output both is false

Method 2: Overload clone() method

The Object parent class has a clone() copy method, but it is a protected type, we need to override it and change it to a public type. In addition, subclasses also need to implement the Cloneable interface to tell the JVM that the class can be copied.

Let's still look at the previous School code and modify the clone function

package com.yyl.javaprogram.copy;

public class School implements Cloneable {
    private String schoolName;
    private int stuNums;
    private Student stu;

    public String getSchoolName() {
        return schoolName;
    }

    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
    }

    public int getStuNums() {
        return stuNums;
    }

    public void setStuNums(int stuNums) {
        this.stuNums = stuNums;
    }

    public Student getStu() {
        return stu;
    }

    public void setStu(Student stu) {
        this.stu = stu;
    }

    @Override
    protected School clone() throws CloneNotSupportedException {
        School school = (School) super.clone();
        school.stu = (Student) stu.clone();
        return school;
    }

    @Override
    public String toString() {
        return "School [schoolName=" + schoolName + ", stuNums=" + stuNums + ", stu=" + stu + "]";
    }
}

Student modifies the clone function

package com.yyl.javaprogram.copy;

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

    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 String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", sex=" + sex + "]";
    }

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

In this way, clone again is to copy all

package com.yyl.javaprogram.copy;

public class DeepCopy {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student student = new Student ();
        student.setName("get");
        student.setAge(15);
        student.setSex("male");
        School school = new School ();
        school.setSchoolName("kkk");
        school.setStuNums(22);
        school.setStu(student);

       School school2 = school.clone();

        // Check two objects have different values
        System.out.println(school.hashCode()==school2.hashCode());
    }
}

Method 3: Serializable serialization

Let's look at the following code

package com.yyl.javaprogram.copy;

import java.io.*;

public class People implements Serializable {

    private String name;
    private Student student;

    public People(String name, Student student) {
        this.name = name;
        this.student = student;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Student getAddress() {
        return student;
    }

    public void setAddress(Student address) {
        this.student = address;
    }

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

        oos.writeObject(this);

        // deserialize
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);

        return ois.readObject();
    }
}

Note that to use serialization to copy objects, objects need to inherit the Serializable interface,
Next we look at the test class

package com.yyl.javaprogram.copy;

public class DeepCopy {
    public static void main(String[] args) throws Exception {
        Student student = new Student ();
        student.setName("get");
        student.setAge(15);
        student.setSex("male");
        People people = new People("ddd",student);


        People people1 = (People) people.deepClone();

        // Check two objects have different values
        System.out.println(people1.hashCode()==people1.hashCode());
    }
}

The result is as follows:

By comparing the hashCode of the people object and the cloned people1 object, it is found that they are also different objects

Tags: Java Distribution Junit programming language

Posted by cmccomas on Sun, 16 Oct 2022 01:47:39 +0530