A deeper understanding of shallow and deep copy in java

brief introduction

Copying objects is a common problem in java.There are two types in java, the base type and the reference type.

java assignments are all passed values, for the underlying type, the specific content will be copied, but for the reference object, the stored value will only point to the address of the actual object, and the copy will only copy the reference address.

Because of the existence of the reference object, it is not always the case as expected.

This article will explore in depth the shallow and deep copies that occur in a copy object.

Copy Interface

All objects in Java inherit from java.lang.Object.The Object object provides a clone method that allows us to copy Java objects.

    protected native Object clone() throws CloneNotSupportedException;

This clone method is native, so we don't need to implement it, but note that the clone method is protected, which means that the clone method can only be seen in the java.lang package or its subclasses.

It is not possible if we want to call the clone method of an object in a program.Because the clone method is defined in an Object, the object does not have a clone method that is visible to the outside world.

JDK's recommendation is that we implement the interface Cloneable, which means that the object can call Object's clone method.

Note that even if you implement the Cloneable interface, you cannot call the clone method of the object in an external program:

public interface Cloneable {
}

Because Cloneable is empty, you are not forced to implement the clone method.

This is a design problem with JDK, which makes the clone method less useful than expected.

First, clone is just a copy of the object, it is simply a copy of the object, and it does not execute its constructor.

Next, clone can cause problems with shallow copies.

Shallow copy caused by clone use

Let's take the example of a shallow copy made by clone. We define an object in an object and try copying:

[@Data](https://my.oschina.net/difrik)
public class Address implements Cloneable{
    private String name;

    //Not a good way
    [@Override](https://my.oschina.net/u/1162528)
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();

    }
}
[@Data](https://my.oschina.net/difrik)
public class CustUser implements Cloneable{
    private String firstName;
    private String lastName;
    private Address address;
    private String[] cars;

    [@Override](https://my.oschina.net/u/1162528)
    public Object clone() throws CloneNotSupportedException{
            return super.clone();
    }
}

In the example above, we defined CustUser and Adress.

 public void testShallowCopy() throws CloneNotSupportedException {
        Address address= new Address();
        address.setName("Beijing Tiananmen");
        CustUser custUser = new CustUser();
        custUser.setAddress(address);
        custUser.setLastName("plum");
        custUser.setFirstName("Thunder");
        String[] cars = new String[]{"Buick","Land tiger"};
        custUser.setCars(cars);

        CustUser custUserCopy=(CustUser) custUser.clone();
        custUserCopy.setFirstName("Mei Mei");
        custUserCopy.setLastName("Korea");
        custUserCopy.getAddress().setName("Summer Palace");
        custUserCopy.getCars()[0]="Audi";

        log.info("{}",custUser);
        log.info("{}",custUserCopy);
    }

Shallow copy We only call CustUser's clone method.Look at the output:

CustUser(firstName=Ray, lastName=Li, address=Address(name=Beijing Summer Palace), cars=[Audi, Land Rover])

CustUser(firstName=Meimei, lastName=Korea, address=Address(name=Beijing Summer Palace), cars=[Audi, Land Rover])

We can see that the Address changes after the copy affect the object being copied.

In the above example, there are two things to focus on: the first is that String is immutable.Strings are immutable whether they are copies or assignments.

Second, in the example above, we defined an array, and you can see that if you just call clone, the array is also a shallow copy.

Using a deep copy of clone

To use a deep copy, you only need to modify CustUser's constructor:

//Not very good way to use it
    [@Override](https://my.oschina.net/u/1162528)
    public Object clone() throws CloneNotSupportedException{
        CustUserDeep custUserDeep=(CustUserDeep)super.clone();
        custUserDeep.address=(Address)address.clone();
        custUserDeep.cars=cars.clone();
            return custUserDeep;
    }

In the overridden clone method, we call the clone methods of CustUser,Address, and Array to copy.

Run the above test code again:

CustUserDeep(firstName=Ray, lastName=Li, address=Address(name=Tiananmen, Beijing), cars=[Buick, Land Rover])

CustUserDeep(firstName=Meimei, lastName=Korea, address=Address(name=Beijing Summer Palace), cars=[Audi, Land Rover])

You can see that address and cars are different, which means that our deep copy was successful.

Do not overridden clone

The example above is achieved by the clone method of overridden Object.

But the best practice is not to overridden clone.So what do we do?

Use constructors to construct new objects:

    //Good way
    Address(Address address){
        this.name=address.name;
    }
//Good way
    CustUserDeep(CustUserDeep custUserDeep){
    this.firstName=custUserDeep.firstName;
    this.lastName=custUserDeep.lastName;
    this.cars=custUserDeep.getCars().clone();
    this.address=new Address(custUserDeep.getAddress());
    }

It is said that it is faster to copy arrays directly with clone, or you can copy arrays as follows:

this.cars= Arrays.copyOf(custUserDeep.getCars(),custUserDeep.getCars().length);

summary

In this paper, the application of shallow and deep copies is explained, and the clone method is discussed in depth.

Examples of this article https://github.com/ddean2009/learn-java-base-9-to-20

Author: Fldean Programs

Links to this article: http://www.flydean.com/java-base-shallow-copy-deep-copy/

Source: Fldean's blog

Welcome to my Public Number: program stuff, more exciting waiting for you!

Tags: Programming Java JDK less github

Posted on Sun, 10 May 2020 18:56:08 -0400 by busterbry