Bigsai is an algorithm that works with Java and data structures. Bigsai is an algorithm that works with Java and data structures.

During development, brushing, and interviewing, we may encounter situations where attributes of one object are assigned to another object. This situation is called copying. Copy and Java memory structure is closely related to understand the depth of Java copy is very necessary!

In copying objects, many beginners may be confused about whether they are copying references or objects. In the copy here is divided into reference copy, shallow copy, deep copy.

Reference copy

A reference copy generates a new object reference address, but both end up pointing to the same object. How to better understand reference copy? Take us as an example. We usually have a given name, but different occasions and people may call us differently, but we know which names belong to “me”!

Of course, here’s a code example to give you a taste of it (I won’t write get, set, etc., for simplicity) :

class Son {
    String name;
    int age;

    public Son(String name, int age) {
        this.name = name;
        this.age = age; }}public class test {
    public static void main(String[] args) {
        Son s1 = new Son("son1".12);
        Son s2 = s1;
        s1.age = 22;
        System.out.println(s1);
        System.out.println(s2);
        System.out.println("The age of s1." + s1.age);
        System.out.println("The age of s2." + s2.age);
        System.out.println("s1==s2" + (s1 == s2));/ / equal}}Copy the code

The output is:

Son@135fbaa4 Son@135fbaa4 AGE of S1 :22 Age of S2 :22 trueCopy the code

Shallow copy

How do you create an object that copies the contents of the target object instead of copying the reference directly?

Shallow copy creates a new object that has nothing to do with the original object itself. The new object is not the same as the original object, but the new object has the same properties as the old object. Specific differences can be seen as follows:

  • If the attribute is of a primitive type (int,double,long, Boolean, etc.), the value of the primitive type is copied.

  • If the property is a reference type, the memory address is copied (that is, the object that copies the reference but does not copy the reference), so if one of the objects changes the address, the other object will be affected.

If a diagram were used to describe shallow copy, it would look something like this:

How do you implement shallow copy? This is as simple as implementing the Cloneable interface and overwriting its clone() method on the class you want to copy.

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

Just call the clone() method of the class. Specific cases are as follows:

class Father{
    String name;
    public Father(String name) {
        this.name=name;
    }
    @Override
    public String toString(a) {
        return "Father{" +
                "name='" + name + '\' ' +
                '} '; }}class Son implements Cloneable {
    int age;
    String name;
    Father father;
    public Son(String name,int age) {
        this.age=age;
        this.name = name;
    }
    public Son(String name,int age, Father father) {
        this.age=age;
        this.name = name;
        this.father = father;
    }
    @Override
    public String toString(a) {
        return "Son{" +
                "age=" + age +
                ", name='" + name + '\' ' +
                ", father=" + father +
                '} ';
    }
    @Override
    protected Son clone(a) throws CloneNotSupportedException {
        return (Son) super.clone(); }}public class test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Father f=new Father("bigFather");
        Son s1 = new Son("son1".13);
        s1.father=f;
        Son s2 = s1.clone();
        
        System.out.println(s1);
        System.out.println(s2);
        System.out.println("s1==s2:"+(s1 == s2));/ / not equal
        System.out.println("s1.name==s2.name:"+(s1.name == s2.name));/ / equal
        System.out.println();

        // But their Father Father is the same as the String name reference
        s1.age=12;
        s1.father.name="smallFather";//s1.father reference unchanged
        s1.name="son222";S1.name =new String("son222"
        System.out.println("s1.Father==s2.Father:"+(s1.father == s2.father));/ / equal
        System.out.println("s1.name==s2.name:"+(s1.name == s2.name));/ / not equalSystem.out.println(s1); System.out.println(s2); }}Copy the code

The running results are as follows:

Son{age=13, name='son1', father=Father{name='bigFather'}} Son{age=13, name='son1', Father= father {name='bigFather'}} father= father {name='bigFather'}} s1==s2:false Son{age=12, name='son222', father= father {name='smallFather'}} Son{age=13, name='son1', father=Father{name='smallFather'}}Copy the code

Unsurprisingly, this shallow copy has the same parts and relationships with the copied object except for the object itself. It is just like twins, two people, but their initial appearance and relationships (parents and relatives) are the same. Note that the name initial == is equal because the initial shallow copy points to the same String, and s1.name=”son222″ changes the reference reference.

Deep copy

To answer the above question, although the two objects are different, some of the internal references are the same. How do you copy the object so that it is completely independent of the original object? I’m going to use our deep copy. Deep copy: When a copy is made of a reference data type, a new object is created and its member variables are copied.

In terms of the specific implementation of deep copy, two methods are provided here, namely, rewriting clone() method and sequence method.

Override the clone() method

If you use the override clone() method to implement deep copy, then all classes in the class with custom reference variables should also implement the Clone () method through the Cloneable interface. You can create a new copy of the string for the character class.

For the above code, the Father class implements the Cloneable interface and overwrites the Clone () method. Son’s clone() method requires a copy of each reference.

/ / Father clone () method
@Override
protected Father clone(a) throws CloneNotSupportedException {
    return (Father) super.clone();
}
/ / Son clone () method
@Override
protected Son clone(a) throws CloneNotSupportedException {
    Son son= (Son) super.clone();// The object to be cloned
    son.name=new String(name);
    son.father=father.clone();
    return son;
}
Copy the code

The other code remains unchanged, and the result is as follows:

Son{age=13, name='son1', father=Father{name='bigFather'}}
Son{age=13, name='son1', father=Father{name='bigFather'}}
s1==s2:false
s1.name==s2.name:false

s1.Father==s2.Father:false
s1.name==s2.name:false
Son{age=12, name='son222', father=Father{name='smallFather'}}
Son{age=13, name='son1', father=Father{name='bigFather'}}
Copy the code
serialization

You can see that deep copy is implemented in this way. But there is a problem with this situation, what if there are too many references or layers?

You can’t write clone() on every object, right? So what to do? By serialization.

After serialization, the binary byte stream is written to a medium (text or byte array), and the data is read from the medium. The original object is written to the medium and copied to the Clone object. The modification of the original object does not affect the Clone object, because the Clone object is read from the medium.

Those familiar with object caching know that we often cache Java objects in Redis, and then possibly generate Java objects from Redis, using serialization and deserialization. Java objects can generally be stored as byte streams or JSON strings and deserialized into Java objects. Serialization stores properties of the object but does not and cannot store information about the object’s location in memory. So all reference objects are recreated when deserialized to Java objects.

On the implementation level, custom classes need to implement the Serializable interface. Define a function in the class requiring deep copy (Son) that returns the class object:

protected Son deepClone(a) throws IOException, ClassNotFoundException {
      Son son=null;
      // Create a byte array buffer in memory in which all data sent to the output stream is stored
      // A buffer of size 32 is created by default
      ByteArrayOutputStream byOut=new ByteArrayOutputStream();
      // Serialized output of the object
      ObjectOutputStream outputStream=new ObjectOutputStream(byOut);// Transfer through byte arrays
      outputStream.writeObject(this);  // Writes the current student object to the byte array

      // Create a byte array buffer in memory where the data read from the input stream is stored
      ByteArrayInputStream byIn=new ByteArrayInputStream(byOut.toByteArray()); // Take an array of bytes as an argument to create
      ObjectInputStream inputStream=new ObjectInputStream(byIn);
      son=(Son) inputStream.readObject(); // Read from the byte array
      return  son;
}
Copy the code

When used, we can call the method we wrote, other unchanged, the effect is:

Son{age=13, name='son1', father=Father{name='bigFather'}}
Son{age=13, name='son1', father=Father{name='bigFather'}}
s1==s2:false
s1.name==s2.name:false

s1.Father==s2.Father:false
s1.name==s2.name:false
Son{age=12, name='son222', father=Father{name='smallFather'}}
Son{age=13, name='son1', father=Father{name='bigFather'}}
Copy the code

Write in the last

Original is not easy, Bigsai please help me with two things:

  1. Like to support, you are sure to be my creative power in nuggets.

  2. Search “Bigsai” on wechat, follow my official account (new people seek support), I will share knowledge and technology on the official account in the first time. Plus I can pull you into the buckle punch group together punch LeetCode.

Thanks for reading, liking and retweeting!