Java deep copy and shallow copy

During the development process, we sometimes encounter the need to copy all the member attributes of an existing object to another object.
For example, object a and object B are both ClassC objects with member variables A and B. now copy and assign object a to B, that is, B.a = A.a; B.b = A.b;

When changing the attribute a or b of b, you may encounter problems: suppose a is the basic data type and b is the reference type.
When changing the value of B.a, there is no problem;
When changing the value of B.b, it will also change the value of A.b, because in the above example, only A.b is assigned to B.b. because it is of b reference type, they point to the same address. This may bury hidden dangers for our use.

Data types in Java are divided into basic data types and reference data types. For these two data types, there is a difference between value passing and reference (address) passing when performing assignment operation, being used as method parameter or return value

According to the object attribute copy degree (basic data type and reference data type), it can be divided into:

  • Shallow Copy
  • Deep Copy

 

I Shallow copy

brief introduction

A shallow copy is a bitwise copy of an object that creates a new object with an exact copy of the original object's attribute values. If the attribute is a basic type, the value of the basic type is copied; If the attribute is a memory address (reference type), the copied is the memory address. Therefore, if one object changes this address, it will affect the other object. That is, the default copy constructor only makes a shallow copy of the object (copy member by member), that is, only copies the object space rather than resources.

characteristic

  • For the member object of basic data type, because the basic data type is passed by value, the attribute value is directly assigned to the new object. Copy of the base type. If one object modifies the value, it will not affect the other.
  • For reference types, such as arrays or class objects, because reference types are passed by reference, shallow copies only assign memory addresses to member variables, which point to the same memory space. Changing one will have an impact on the other.

 

As shown in the figure:

 

Code implementation

To implement copying, you need to make the class of the copied object implement the clonable interface and override the clone() method.

Examples are as follows

public class Subject {
    private String name;
    private int age;
    public Subject(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
    public String toString() {
        return "Subject{" +"hashCode=" + this.hashCode() +", full name='" + name + '\'' + ", Age=" + age + '}';
    }
}

 

public class Student implements Cloneable{
    //Reference data
    private Subject subject;
    private String name;
    //Basic data type
    private int age;

    public Subject getSubject() {
        return subject;
    }

    public void setSubject(Subject subject) {
        this.subject = subject;
    }

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

    @Override
    public String toString() {
        return "Student{" +"hashCode=" + this.hashCode()+", subject=" + subject + ", full name='" + name + '\'' +", Age=" + age +'}';
    }
}

Test class

public class ShallowCopy {
    public static void main(String[] args) throws CloneNotSupportedException {
        Subject subject = new Subject("Lee",1);
        Student student1 = new Student();
        student1.setSubject(subject);
        student1.setName("Zhang");
        student1.setAge(13);
        // student2 is copied from student1

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

        student2.setName("money");
        student2.setAge(15);
        System.out.println("student1:" + student1);
        System.out.println("student2:" + student2);

    }
}

Operation results:

As can be seen from the output results, through student1 After clone () copies the object, student2 and student1 are two different objects. The modification of the basic data types of student1 , and student2 , does not affect each other, but the modification of the reference type subject will affect each other.

II Deep copy

brief introduction

Although the clone() method can copy objects, note that the clone() method defaults to shallow copy behavior, just like the above example. If you want to implement deep copy, you need to override the clone() method to implement the deep traversal copy of the reference object and conduct carpet search.

Deep copy: when copying reference type member variables, it creates an independent memory space for the data members of reference type to copy the real content.

characteristic

  • For the member object of basic data type, because the basic data type is passed by value, the attribute value is directly assigned to the new object. For a copy of the base type, if one object modifies the value, it will not affect the other (like a shallow copy).
  • For reference types, such as arrays or class objects, deep copy creates a new object space, and then copies the contents, so they point to different memory spaces. Changing one will not affect the other.
  • For multi-layer objects, each object needs to implement clonable and override the clone() method, so as to realize the serial layer by layer copy of the object.
  • Deep copy is slower and more expensive than shallow copy.

As shown in the figure:

 

code implementation

For the member variable Subject of Student's reference type, you need to implement clonable and override the clone() method.

public class Subject implements Cloneable{
    private String name;
    private int age;
    public Subject(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();
    }

    @Override
    public String toString() {
        return "Subject{" +"hashCode=" + this.hashCode() +", full name='" + name + '\'' + ", Age=" + age + '}';
    }
}

In the clone() method of Student, you need to get the new object generated after copying yourself, and then call the copy operation for the reference type of the new object to realize the deep copy of the member variables of the reference type.
 

public class Student implements Cloneable{
    //Reference data
    private Subject subject;
    private String name;
    //Basic data type
    private int age;

    public Subject getSubject() {
        return subject;
    }

    public void setSubject(Subject subject) {
        this.subject = subject;
    }

    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 {
        Student student = (Student) super.clone();
        student.subject = (Subject) subject.clone();
        return student;
    }

    @Override
    public String toString() {
        return "Student{" +"hashCode=" + this.hashCode()+", subject=" + subject + ", full name='" + name + '\'' +", Age=" + age +'}';
    }
}

Test class

public class DeepCopy {
    public static void main(String[] args) throws CloneNotSupportedException {
        Subject subject = new Subject("Lee",1);
        Student student1 = new Student();
        student1.setSubject(subject);
        student1.setName("Zhang");
        student1.setAge(13);
        // student2 is copied from student1

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

        student2.setName("money");
        student2.setAge(15);
        System.out.println("student1:" + student1);
        System.out.println("student2:" + student2);

    }
}

Operation results


After deep copy, student1 and student2 are completely independent and free from mutual interference.  

Keywords: Java

Added by thebay on Sat, 01 Jan 2022 12:23:22 +0200