java object cloning and replication

Original link: https://blog.csdn.net/ztchun/article/details/79110096

Let me briefly describe and summarize: when you want to directly give the existing value of one object to another object, you don't want to change the second object to affect the local qualification object, but this result will be caused if you operate improperly. Therefore, we need to understand the principle of deep cloning and shallow cloning of java objects.

1. Overview

In the actual programming process, we often encounter this situation: there is an object A, which has contained some valid values at A certain time. At this time, A new object B exactly the same as A may be required, and any change to B thereafter will not affect the value in A, that is, A and B are two independent objects, but the initial value of B is determined by object A. For example, the following program shows the situation:

class Student {  
    private int number;  
  
    public int getNumber() {  
        return number;  
    }  
  
    public void setNumber(int number) {  
        this.number = number;  
    }  
      
}  
public class Test {   
    public static void main(String args[]) {  
        Student stu1 = new Student();  
        stu1.setNumber(12345);  
        Student stu2 = stu1;  
        stu1.setNumber(54321);  
        System.out.println("Student 1:" + stu1.getNumber());  
        System.out.println("Student 2:" + stu2.getNumber());  
    }  
}

 

result:

Student 1:54321
Student 2:54321

Why did the student number of student 2 and student 1 change?
The reason lies in the sentence (stu2 = stu1). The function of this statement is to assign the reference of stu1 to stu2,
Thus, stu1 and stu2 point to the same object in the memory heap. As shown in the figure:

So, how can you copy an object cleanly and clearly. In the Java language, simple assignment statements can not meet this demand. There are many ways to meet this demand,
(1) Add the value of object A to object B through the set method;
(2) By rewriting Java Method clone() in lang.Object class;
(3) Via org apache. The tool classes BeanUtils and PropertyUtils in commons copy objects;
(4) Realize the replication of objects through serialization.

#2. Add the value of object A to object B through the set method
Assign values to attributes one by one. This example sets an attribute for demonstration:

Student stu1 = new Student();  
stu1.setNumber(12345);  
Student stu2 = new Student();  
stu2.setNumber(stu1.getNumber());

, it's convenient to assign values to attributes one by one with few attributes, but when there are many attributes, you need to get and set all the time, which is very troublesome.

#3. Rewrite Java Method clone() in lang.Object class
First, let's introduce two different cloning methods, shallow clone and deep clone.

In the Java language, data types are divided into value types (basic data types) and reference types. Value types include simple data types such as int, double, byte, boolean and char, and reference types include complex types such as classes, interfaces and arrays. The main difference between shallow cloning and deep cloning is whether it supports the replication of member variables of reference type. The two are described in detail below.

##3.1 shallow cloning
General steps:

  1. The copied class needs to implement the Clonenable interface (if it is not implemented, the CloneNotSupportedException exception will be thrown when calling the clone method), which is a marked interface (without any methods)

  2. Override the clone() method and set the access modifier to public. Method The clone() method gets the required replication object. (native is a local method)

class Student implements Cloneable{  
    private int number;  
  
    public int getNumber() {  
        return number;  
    }  
  
    public void setNumber(int number) {  
        this.number = number;  
    }  
      
    @Override  
    public Object clone() {  
        Student stu = null;  
        try{  
            stu = (Student)super.clone();  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return stu;  
    }  
}  
public class Test {  
    public static void main(String args[]) {  
        Student stu1 = new Student();  
        stu1.setNumber(12345);  
        Student stu2 = (Student)stu1.clone();  
          
        System.out.println("Student 1:" + stu1.getNumber());  
        System.out.println("Student 2:" + stu2.getNumber());  
          
        stu2.setNumber(54321);  
      
        System.out.println("Student 1:" + stu1.getNumber());  
        System.out.println("Student 2:" + stu2.getNumber());  
    }  
}  

 

result:
Student 1:12345
Student 2:12345
Student 1:12345
Student 2:54321

In shallow cloning, if the member variable of the prototype object is a value type, a copy will be copied to the cloned object; If the member variable of the prototype object is a reference type, copy the address of the reference object to the clone object, that is, the member variables of the prototype object and the clone object point to the same memory address.

Simply put, in shallow cloning, when an object is copied, only its own and the member variables of the value type contained therein are copied, while the member object of the reference type is not copied.


In the Java language, shallow cloning can be achieved by overriding the clone() method of the Object class.
##3.2 deep cloning

package abc;  
  
class Address {  
    private String add;  
  
    public String getAdd() {  
        return add;  
    }  
  
    public void setAdd(String add) {  
        this.add = add;  
    }   
}  
  
class Student implements Cloneable{  
    private int number;  
  
    private Address addr;  
      
    public Address getAddr() {  
        return addr;  
    }  
  
    public void setAddr(Address addr) {  
        this.addr = addr;  
    }  
  
    public int getNumber() {  
        return number;  
    }  
  
    public void setNumber(int number) {  
        this.number = number;  
    }  
      
    @Override  
    public Object clone() {  
        Student stu = null;  
        try{  
            stu = (Student)super.clone();   //Shallow replication  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }   
        return stu;  
    }  
}  
public class Test {  
      
    public static void main(String args[]) {  
          
        Address addr = new Address();  
        addr.setAdd("Hangzhou");  
        Student stu1 = new Student();  
        stu1.setNumber(123);  
        stu1.setAddr(addr);  
          
        Student stu2 = (Student)stu1.clone();  
          
        System.out.println("Student 1:" + stu1.getNumber() + ",address:" + stu1.getAddr().getAdd());  
        System.out.println("Student 2:" + stu2.getNumber() + ",address:" + stu2.getAddr().getAdd());  
          
        addr.setAdd("West Lake District");  
          
        System.out.println("Student 1:" + stu1.getNumber() + ",address:" + stu1.getAddr().getAdd());  
        System.out.println("Student 2:" + stu2.getNumber() + ",address:" + stu2.getAddr().getAdd());  
    }  
}

 

result:
Student 1:123, address: Hangzhou
Student 2:123, address: Hangzhou
Student 1:123, address: West Lake District
Student 2:123, address: West Lake District

How come the addresses of both students have changed?

The reason is that shallow copy only copies the reference of addr variable and does not really open up another space. Copy the value and then return the reference to the new object.

In order to achieve real replication objects, rather than pure reference replication. We need to make the Address class replicable and modify the clone method. The complete code is as follows:

package abc;  
  
class Address implements Cloneable {  
    private String add;  
  
    public String getAdd() {  
        return add;  
    }  
  
    public void setAdd(String add) {  
        this.add = add;  
    }  
      
    @Override  
    public Object clone() {  
        Address addr = null;  
        try{  
            addr = (Address)super.clone();  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        return addr;  
    }  
}  
  
class Student implements Cloneable{  
    private int number;  
  
    private Address addr;  
      
    public Address getAddr() {  
        return addr;  
    }  
  
    public void setAddr(Address addr) {  
        this.addr = addr;  
    }  
  
    public int getNumber() {  
        return number;  
    }  
  
    public void setNumber(int number) {  
        this.number = number;  
    }  
      
    @Override  
    public Object clone() {  
        Student stu = null;  
        try{  
            stu = (Student)super.clone();   //Shallow replication  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }  
        stu.addr = (Address)addr.clone();   //Deep replication  
        return stu;  
    }  
}  
public class Test {  
      
    public static void main(String args[]) {  
          
        Address addr = new Address();  
        addr.setAdd("Hangzhou");  
        Student stu1 = new Student();  
        stu1.setNumber(123);  
        stu1.setAddr(addr);  
          
        Student stu2 = (Student)stu1.clone();  
          
        System.out.println("Student 1:" + stu1.getNumber() + ",address:" + stu1.getAddr().getAdd());  
        System.out.println("Student 2:" + stu2.getNumber() + ",address:" + stu2.getAddr().getAdd());  
          
        addr.setAdd("West Lake District");  
          
        System.out.println("Student 1:" + stu1.getNumber() + ",address:" + stu1.getAddr().getAdd());  
        System.out.println("Student 2:" + stu2.getNumber() + ",address:" + stu2.getAddr().getAdd());  
    }  
}

result:
Student 1:123, address: Hangzhou
Student 2:123, address: Hangzhou
Student 1:123, address: West Lake District
Student 2:123, address: Hangzhou

In deep clone, no matter whether the member variable of the prototype object is a value type or a reference type, it will be copied to the cloned object. Deep clone will also copy all reference objects of the prototype object to the cloned object.

Simply put, in deep cron, in addition to the object itself being copied, all member variables contained in the object will also be copied.

In the Java language, if deep cloning is needed, it can be implemented by overriding the clone() method of the Object class or by serialization.

(if the reference type also contains many reference types, or the inner reference type class contains reference types, it will be troublesome to use the clone method. At this time, we can use serialization to realize the deep cloning of objects.)

#4. Tool classes BeanUtils and PropertyUtils for object replication

Student stu1 = new Student();  
stu1.setNumber(12345);  
Student stu2 = new Student(); 
BeanUtils.copyProperties(stu2,stu1);

No matter how many attributes are written in this way, it only needs one line of code. It's very convenient! In addition to BeanUtils, there is a tool class named PropertyUtils. It also provides the copyProperties() method, which is very similar to the method with the same name of BeanUtils. The main difference is that BeanUtils provides type conversion function, that is, when two JavaBean s have different properties with the same name, they will convert within the range of supported data types. PropertyUtils does not support this function, but it will be faster. In actual development, BeanUtils is more commonly used and has a lower risk of making mistakes.

#5. Replication of objects through serialization
Serialization is the process of writing an object to a stream. The object written to the stream is a copy of the original object, which still exists in memory. The copy realized by serialization can copy not only the object itself, but also the member object referenced by it. Therefore, deep cloning can be realized by writing the object to a stream through serialization and reading it out from the stream. It should be noted that for objects that can be serialized, their classes must implement the Serializable interface, otherwise the serialization operation cannot be realized

Posted by mogen on Thu, 19 May 2022 08:46:33 +0300