The article directories

  • What is shallow copy and deep copy
  • In Java clone ()
    • Clone () method on Object
    • Shallow copy Example
    • Deep-copy Examples
  • conclusion

What is shallow copy and deep copy

The first thing to understand is that both shallow and deep copies are operations on an existing object. So let’s look at the concept of shallow copy and deep copy.

In Java, in addition to the base datatype (metatype), there is a reference datatype, the instance object of a class. Normally when you use the = sign to do an assignment. For a primitive data type, you actually copy its value, but for an object, you’re just assigning a reference to the object, passing a reference to the original object, they’re actually referring to the same object.

The distinction between shallow copy and deep copy is made on this basis. If only the basic data type is copied, and the reference data type is only passed by reference, without actually creating a new object, it is considered as a shallow copy. Conversely, when a copy of a reference data type creates a new object and copies its member variables, it is considered a deep copy.

So by now, you should know that shallow copy and deep copy are just different operations on reference data types of class instance objects when copying objects.

To sum up:

1. Shallow copy: The basic data type is passed by value and the reference data type is copied by reference. This is a shallow copy.



2. Deep copy: Passes the value of the basic data type, creates a new object for the reference data type, and copies its content. This is the deep copy.

In Java clone ()

Clone () method on Object

In Java, all classes inherit from Object, and on Object there is a clone() method that is declared protected, so we can use it in subclasses.

Both shallow and deep copies require the clone() method to complete the operation.

Its implementation is very simple, it limits all call clone () method of the object, must implement Cloneable interface, whether will throw CloneNotSupportedException this exception. The internalClone() method is eventually called to complete the operation. The internalClone() method is actually a native method. We don’t need to dig too deep into this, just know that it can clone() an object to get a new object instance

The Cloneable interface, on the other hand, doesn’t need to implement any methods. It can simply be understood as a tag that allows the object to be copied by the developer

Shallow copy Example

First create a class called FatherClass, implement the Cloneable interface to it, and override the clone() method.

public class FatherClass implements Cloneable{
    public String name;
    public int age;
    public ChildClass child;

    @NonNull
    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        return super.clone(); }}Copy the code
public class ChildClass {
    public String name;
    public int age;
}
Copy the code

Then create a new FatherClass object using the clone() method

FatherClass fatherClassA = new FatherClass();
        fatherClassA.name = "Normal Joe";
        fatherClassA.age = 30;
        fatherClassA.child = new ChildClass();
        fatherClassA.child.name = "The Outlaw John.";
        fatherClassA.child.age = 18;

        try {
            FatherClass fatherClassB = (FatherClass) fatherClassA.clone();
            Log.d("TTT"."fatherClassA == fatherClassB:" + (fatherClassA == fatherClassB));
            Log.d("TTT"."fatherClassA hash:" + fatherClassA.hashCode());
            Log.d("TTT"."fatherClassB hash:" + fatherClassB.hashCode());
            Log.d("TTT"."fatherClassA name:" + fatherClassA.name);
            Log.d("TTT"."fatherClassB name:" + fatherClassB.name);
            Log.d("TTT"."= = = = = = = = = = = = = = =");
            Log.d("TTT"."A.child == B.child:" + (fatherClassA.child == fatherClassB.child));
            Log.d("TTT"."fatherA.child hash:" + fatherClassA.child.hashCode());
            Log.d("TTT"."fatherB.child hash:" + fatherClassB.child.hashCode());

        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
Copy the code

Finally, look at the output Log:

FatherClassA == fatherClassB:false fatherClassA hash:156329482 fatherClassB hash:175877755 fatherClassA name: normal FatherClassB name: normal =============== a.child == B.child:true fathera. child Hash :66385048 fatherb. Child Hash :66385048

Before splitting lines, the clone() method is used, and as you can see from the difference between == and hashCode, it actually creates a new object.

But this is only a shallow copy operation.

The output of child shows that the child objects of A and B actually refer to the same object, but the reference is passed, so this is A shallow copy

Deep-copy Examples

So how do you make a deep copy? There are two common methods: 1) serialization of the object, and then deserialization, we can get the new object, but the serialization rules need to be written by ourselves. 2. Continue to use the clone() method. Since the clone() method is rewritten by us, we can actually clone() the variables of reference type in it again.

Go ahead and rewrite the Demo above to make ChildClass implement Cloneable as well.

public class ChildClass implements Cloneable{
    public String name;
    public int age;

    @NonNull
    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        return super.clone(); }}Copy the code

Then modify FatherClass

public class FatherClass implements Cloneable{
    public String name;
    public int age;
    public ChildClass child;

    @NonNull
    @Override
    protected Object clone(a) throws CloneNotSupportedException {
        FatherClass fatherClass = (FatherClass)super.clone();
        fatherClass.child = (ChildClass)this.child.clone();
        returnfatherClass; }}Copy the code

The most important code is in fatherclass.clone (), which does a clone() operation on the child.

Look at the log

FatherClassA == fatherClassB:false fatherClassA hash:156329482 fatherClassB hash:175877755 fatherClassA name: normal FatherClassB name: normal =============== a.child == B.child:false fathera. Child Hash :66385048 fatherb. Child Hash :123905265

As you can see, there is a shallow copy of Child, but a deep copy of FatherClass.

In fact, the idea of deep copy is similar. Whether serialization or clone() is used, in fact, we need to write our own copy rules, and finally achieve the purpose of deep copy.

The clone() method is recommended if you want to implement deep copy, so that each class can maintain its own, and you don’t need to worry about whether other parameters in other internal objects also need to be clone().

conclusion

At this point, the concept of shallow copy and deep copy in Java has been clarified.

In fact, shallow copy and deep copy are only relative. If there are only basic data types in an object, using clone() is a deep copy of the object. If there are reference data types in the object, using Clone () is a shallow copy.

Detail deep and shallow copies of Java