Design pattern - prototype pattern (deep copy and shallow copy)

Prototype pattern of design pattern

1. Overview of prototype mode

Prototype pattern is used to create duplicate objects while ensuring performance. It belongs to the creation mode, which provides the best way to create objects.

The prototype pattern is relatively simple to implement in Java. You only need to implement an interface clonable and rewrite the clone() method in the interface to complete the prototype pattern.

2. Code implementation

2.1 implementation prototype mode

import java.util.List;

/*
 * In order to reduce the amount of code, lombok is used to automatically generate code.
 */

@Data //Generate set/get method
@ToString //Override toString()
@NoArgsConstructor //Parameterless constructor
@AllArgsConstructor //Full parameter constructor


//Step 1: implement clonable interface
public class Student implements Cloneable {

    private int age;
    private char gender;
    private List<Integer> scores;
	
    /*
     * The second step is to override the clone method and directly call the clone() method of the parent class (Object).
     * Object The internal clone() method is modified by native.
     */
    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }
}

2.2 testing

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {
        List<Integer> scores = new ArrayList<>();
        scores.add(1);
        scores.add(2);
        scores.add(3);
		
        //Original object
        Student student = new Student(14, 'male', scores);
		
        //Call the clone() method to generate a clone object
        Student cloneStudent = student.clone();
		
        //The information inside the two objects is exactly the same
        System.out.println("primary student information: " + student);
        System.out.println("Cloned student: " + cloneStudent);
        
        
        //This is false, indicating that the cloned object and the original object are two different objects in the heap.
        System.out.println("Is the cloned object the same as the original object: " + (cloneStudent == student));

        
        
// ---Let's modify some properties inside the cloned object to see if they will affect the original object.

        //Modify basic data (int) type attribute
        cloneStudent.setAge(3);

        //Modify the reference type (List) property
        List<Integer> cscores = cloneStudent.getScores();
        cscores.add(4);

        System.out.println("After modifying the cloned object, the original student information: " + student);
        System.out.println("After modifying the cloned object, cloneStudet Information about: " + cloneStudent);
		
        //true
        System.out.println("Comparison between original object and cloned object scores(List)Are the addresses the same : " + (student.getScores() == cloneStudent.getScores()));
    }
}

/*

Original student information: Student(age=14, gender = male, scores=[1, 2, 3])
Cloned student: Student(age=14, gender = male, scores=[1, 2, 3])
Whether the cloned object and the original object are the same object: false

//Modifying the basic attribute type has no effect on the original object, but modifying the internal reference type variable will affect the original object.
After modifying the cloned object, the original student information: Student(age=14, gender = male, scores=[1, 2, 3, 4])
After modifying the cloned object, the information of clonestadet: Student(age=3, gender = male, scores=[1, 2, 3, 4])

//The two internal List properties refer to the same object
 Whether the scores(List) addresses of the original object and the cloned object are the same: true
*/

2.3 summary

  • When cloning is completed, a new object is actually created in the heap, that is, the address of the cloned object is different from that of the original object in the heap.
  • If there are reference type variables inside the original object (such as the above List), when cloning, only the address of the reference type object inside the original object will be assigned to the reference variable inside the clone object, that is, the list attribute addresses of the above original object and the clone object are the same, and a list will not be created in the heap. This is called shallow copy.

3. Deep copy and shallow copy

Reference Luffy

3.1 what are deep copy and shallow copy

  • Data is divided into basic data type and reference data type. Basic data type: data is directly stored in the stack; Reference data type: the reference address of the object is stored in the stack, and the real object data is stored in the heap memory.
  • Shallow copy: for basic data types: copy data values directly; For reference data type: only the reference address of the object is copied. The old and new objects point to the same memory address. Modify the value of one object and the value of the other object will change.
  • Deep copy: for basic data types: directly copy data values; As like as two peas, the new data is used to create new memory space. In the new memory space, a new object is copied. The old and new objects do not share memory. Modifying the value of one object will not affect another object.
  • Deep copy is slower and more expensive than shallow copy.

3.2 realize deep copy

Shallow copy is implemented through clonable interface, and deep copy is implemented through serializable.

/*
 * Note to implement the Serializable interface.
 */
public class Student implements Serializable {

    private int age;
    private char gender;
    private List<Integer> scores;

    /*
    *  Custom deep copy method.
    * */
    public Student deepClone() {
        try {
            // Output (serialization)
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(this);
            // Input (deserialization)
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Student Student = (Student) ois.readObject();
            return Student;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

test

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {

        List<Integer> scores = new ArrayList<>(Arrays.asList(1, 2, 3));
        Student student = new Student(1, 'male', scores);

        Student cloneStudent = student.deepClone();
		
        //false
        System.out.println(student == cloneStudent);
		
        //false deep copy succeeded!!!
        System.out.println(student.getScores() == cloneStudent.getScores());

    }
}

The list memory address inside the original object is different from the list address inside the cloned object, indicating that the deep copy is successful!!!

Keywords: Java Design Pattern

Added by k0z on Wed, 12 Jan 2022 05:05:11 +0200