Comparison of java replication methods

1. Background

In the actual programming process, we often encounter this situation: there is an object A, at A certain time A already contains some valid values, at this time, we may need A new object B exactly the same as A, and any change to B will not affect the value in A, that is to say, A and B are two independent objects, but the initial value of B is determined by the object A.

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());  
    }  
}

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

So, how can you copy an object cleanly and cleanly. In the Java language, using simple assignment statements can not meet this need. There are many ways to meet this demand,
(1) the values of object A are added to object B through set method;
(2) Rewrite the method clone() in java.lang.Object class;
(3) copy the objects through the tool classes BeanUtils and PropertyUtils in org.apache.commons;
(4) copy the object by serialization.
1. The values of object A are added to object B through set method, and the attributes are assigned one by one. We found that it is convenient to assign fewer attributes one by one, but when there are more attributes, you need to get and set all the time, which is very troublesome.

2. Rewrite the method clone() in the java.lang.Object class
First, introduce two different cloning methods, shallow clone and deep clone.

In 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, char, and reference types include complex types such as class, interface, array, etc. The main difference between shallow cloning and deep cloning is whether it supports the replication of member variables of reference type. The following details the two.

2.1 shallow cloning
General steps:

The copied class needs to implement the Clonenable interface (if not, the CloneNotSupportedException exception will be thrown when calling the clone method). This interface is a tag interface (no methods included)

Override the clone() method with the access modifier set to public. The super.clone() method is invoked to get the copied object. (native is the 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());  
    }  
} 

In shallow cloning, if the member variable of the prototype object is of value type, one copy will be copied to the clone object; if the member variable of the prototype object is of reference type, one copy of the address of the reference object will be copied to the clone object, that is to say, the member variable 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 the member variables of its own and the value type it contains are copied, while the member objects of the reference type are not copied. In the Java language, shallow cloning can be achieved by overriding the clone() method of the Object class.
2.2 deep cloning

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 copy  
        }catch(CloneNotSupportedException e) {  
            e.printStackTrace();  
        }   
        return stu;  
    }  
}  
public class Test {  
      
    public static void main(String args[]) {  
          
        Address addr = new Address();  
        addr.setAdd("Hangzhou City");  
        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("Xihu District");  
          
        System.out.println("Student 1:" + stu1.getNumber() + ",address:" + stu1.getAddr().getAdd());  
        System.out.println("Student 2:" + stu2.getNumber() + ",address:" + stu2.getAddr().getAdd());  
    }  
}

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 true replication of 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:

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 copy  
        }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 City");  
        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("Xihu District");  
          
        System.out.println("Student 1:" + stu1.getNumber() + ",address:" + stu1.getAddr().getAdd());  
        System.out.println("Student 2:" + stu2.getNumber() + ",address:" + stu2.getAddr().getAdd());  
    }  
}

In deep clone, no matter the member variable of prototype Object is value type or reference type, it will copy one copy to clone Object, and deep clone will copy all reference objects of prototype Object to clone Object. Simply put, in deep klong, all member variables contained in an Object are copied, except for the Object itself. In the Java language, if deep cloning is needed, it can be realized by overriding the clone() method of the Object class, or by serialization. (if there are many reference types in the reference type, or there are reference types in the inner reference type class, it will be troublesome to use the clone method. At this time, we can use serialization to achieve deep cloning of objects.)

3. 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 you write, you only need 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 the type conversion function, that is, when the same name property of two JavaBean s is of different types, it is converted within the range of supported data types, which is not supported by PropertyUtils , but it will be faster. In actual development, BeanUtils are more commonly used and the risk of error is lower.

4. Copy objects by serialization
Serialization is the process of writing objects to the stream. The objects written to the stream are a copy of the original objects, which still exist in memory. The copy realized by serialization can not only copy the object itself, but also the member object it references. 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 the class of an object that can be serialized must implement the Serializable interface, otherwise the serialization operation cannot be implemented.

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

Tags: Programming Java Apache

Posted on Fri, 08 Nov 2019 03:52:03 -0500 by Tarsonis21