Shallow and deep copies of Java

In Java, all classes inherit from Object, and Object has the Clone method, which is protected, so if we wanted to use it we’d have to override it and declare it public. Must be in the class implements the Cloneable interface, implementation of Clone. Otherwise the Java lang. CloneNotSupportedException abnormalities, Cloneable interface is in Java. The lang automatically be imported, The Clone () method needs to be implemented for both shallow and deep copies.

If the clone() method is not overridden, the clone() method is called with a shallow copy (all reference objects remain unchanged, meaning that changes to these objects in the prototype directly affect the copied objects). Overrides the clone() method, which typically makes a shallow copy by calling super.clone() and then copying the mutable objects to make a deep copy.

Shallow copy

Clone automatically makes shallow copies. Let’s look at the code:

public class Resume implements Cloneable {

    private String name;
    private String sex;
    private String age;
    private String timeArea;
    private String company;

    public Resume(String name) {
        this.name = name;
    }

    // Set personal information
    public void setPersonInfo(String age, String sex) {
        this.age = age;
        this.sex = sex;
    }

    // Set work history
    public void setWorkExperience(String timeArea, String company) {
        this.timeArea = timeArea;
        this.company = company;
    }

    / / show
    public void display(a) {
        System.out.println(name + "" + sex + "" + age);
        System.out.println("Work Experience:" + timeArea + "" + company);
    }

    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        return super.clone();
    }
    
    
    public static void main(String args[]) throws CloneNotSupportedException {
        Resume r = new Resume("Big bird");
        r.setPersonInfo("28"."Male");
        r.setWorkExperience("1998-2000"."XX company");
        Resume r2 = (Resume)r.clone();
        r2.setWorkExperience("2000-2003".YY enterprise "");
        Resume r3 = (Resume)r.clone();
        r3.setWorkExperience("2003-2020".ZZ "company"); r.display(); r2.display(); r3.display(); }}Copy the code

The result is:

Big Bird Male 28 Work experience: 1998-2000 XX Company Big Bird Male 28 Work experience: 2000-2003 YY enterprise Big Bird male 28 Work experience: 2003-2020 ZZ companyCopy the code

Encapsulate WorkExperience as a class and see what the difference is:

public class Resume implements Cloneable {

    private String name;
    private String sex;
    private String age;
    private WorkExperience we = null;

    public Resume(String name) {
        this.name = name;
        we = new WorkExperience();
    }

    // Set personal information
    public void setPersonInfo(String age, String sex) {
        this.age = age;
        this.sex = sex;
    }

    public void setWorkExperience(String timeArea, String company) {
        we.setTimeArea(timeArea);
        we.setCompany(company);
    }


    / / show
    public void display(a) {
        System.out.println(name + "" + sex + "" + age);
        System.out.println("Work Experience:" + we.getTimeArea() + "" + we.getCompany());
    }

    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        return super.clone();
    }
    
    
    
    public static void main(String args[]) throws CloneNotSupportedException {
        Resume r = new Resume("Big bird");
        r.setPersonInfo("28"."Male");
        r.setWorkExperience("1998-2000"."XX company");
        Resume r2 = (Resume)r.clone();
        r2.setPersonInfo("31"."Male");
        r2.setWorkExperience("2000-2003".YY enterprise "");
        Resume r3 = (Resume)r.clone();
        r3.setWorkExperience("2003-2020".ZZ "company"); r.display(); r2.display(); r3.display(); }}class WorkExperience {
    private String timeArea;
    private String company;

    public String getTimeArea(a) {
        return timeArea;
    }

    public void setTimeArea(String timeArea) {
        this.timeArea = timeArea;
    }

    public String getCompany(a) {
        return company;
    }

    public void setCompany(String company) {
        this.company = company; }}Copy the code

The output of the result is:

Work experience: 2003-2020 ZZ Male 31 Work experience: 2003-2020 ZZ Male 28 Work experience: 2003-2020 ZZ companyCopy the code

As you can see, this will only refer the reference to that object if there are other classes in the cloned class, without actually cloning

Super.clone () does a bitwise copy(binary copy) of the original object to include references. This can cause problems. If a property inside is a mutable object, then the original object changes and the cloned object changes too. So after super.clone() is called, you usually need to copy the mutable object again.

Error: Java: clone() is protected access control in java.lang.object


Deep copy:

So how do you make a deep copy?

There are two commonly used schemes:

  • We can serialize this object and then deserialize it back to get a new object. The rules for serialization need to be written ourselves.

  • Continue using the clone() method. Since we’re rewriting the clone() method, we can actually do a clone() again on variables of reference type within it. Go ahead and rewrite the Demo above to make ChildClass implement Cloneable as well.

    You need to change the code to the following:

    public class Resume implements Cloneable {
        
        @Override
        protected Object clone(a) throws CloneNotSupportedException {
            Resume r = (Resume)super.clone();
            r.we = (WorkExperience)this.we.clone();
            returnr; }}class WorkExperience implements Cloneable {
    
        @Override
        protected Object clone(a) throws CloneNotSupportedException {
            return super.clone(); }}Copy the code

    When clone of both methods is overridden, the result is ready for deep copy:

    Big Bird Male 28 Work experience: 1998-2000 XX Company Big Bird Male 31 Work experience: 2000-2003 YY enterprise big Bird male 28 Work experience: 2003-2020 ZZ companyCopy the code

Conclusion:

When clone() is called at each level along the super.clone() chain, object.clone () is called.

To do this, think of the semantics of the JVM’s native implementation object.clone () as taking this reference, reflecting it to find all the fields of the Object instance, and copying them field by field.

In HotSpot VM, object.clone () has different implementations at different optimization levels. The least optimized version does this: GetClass () == x.lone. GetClass () == x.goetclass () == x.lone. It then blindly copies the contents of the object body from the source to the target as if it were an array copy, bitwise copy.

Super.clone () creates a new empty Object of the same type based on the current Object type. The values of the fields of the current object are then copied to the new object one by one and returned to the clone() call. The shallow copy effect of super.clone() is implemented with object.clone ().