Detailed explanation of Java cloning technology, the difference and implementation of deep copy and shallow copy

What is cloning and why is cloning used in programming

Cloning refers to creating a copy of an object such that the newly created object is identical in content to the original object. In programming, cloning is one of the commonly used techniques, it has the following important uses and advantages:

  1. Duplicate Objects: Use cloning to create a new object that is identical to the original object, including the object's properties and state. This allows the new object to be modified, manipulated, passed on, etc. without affecting the original object. This is useful in some scenarios to avoid recreating and initializing an object.

  2. Isolation and Protection: With cloning, a copy of an object is created that is independent of the original. In this way, when the cloned object is modified, the original object will not be affected, thereby achieving isolation between objects. This is of great significance for concurrent operations in a multi-threaded environment or for protecting important data.

  3. Performance optimization: Sometimes, the performance of the program can be improved by cloning objects. In some scenarios, the creation and initialization process of the object may be time-consuming. If the object needs to be used multiple times, the repeated creation and initialization process can be avoided by cloning the original object, thereby improving the execution efficiency of the program.

  4. Prototype pattern: Cloning has an important role in the design pattern, namely the prototype pattern. The prototype pattern creates an instance of an object by cloning it, rather than using a traditional constructor. This allows for more flexible object creation and avoids frequent subclassing.

In programming, object cloning is usually implemented by implementing the Cloneable interface and rewriting the clone method. However, it should be noted that there may be a difference between deep copy and shallow copy in the cloning operation, and the appropriate cloning method needs to be selected according to actual needs when using it.

What is deep copy and shallow copy

Deep copy (Deep Copy) and shallow copy (Shallow Copy) are two concepts that are often encountered in the clone (Clone) operation, and they describe how the clone operation handles the internal references of the object.

  1. Shallow Copy:

    • Shallow copy means that in the cloning operation, only the object itself and the properties of the basic data type inside the object are copied, and the properties of the reference type inside the object are not copied.
    • A shallow copy simply creates a new object that shares access to properties of the same reference type as the original object. If the reference-type properties of the original object are modified, the shallow-copied object will also be affected.
    • In a shallow copy, the new object and the original object point to the same memory area, so modifications to one object may affect the other.
  2. Deep Copy (Deep Copy):

    • Deep copy means that in the cloning operation, in addition to copying the object itself and the attributes of the basic data type inside the object, it is also necessary to recursively copy the attributes of the reference type inside the object. That is, the properties of all reference types are deeply cloned.
    • Deep copy creates a completely independent new object, which has no relationship with the original object, and the modification of the new object and the original object does not affect each other.
    • In a deep copy, the new object and the original object correspond to different memory areas, and there is no reference relationship between them, so modifying one of the objects will not affect the other.

In order to achieve deep copy, it is necessary to recursively copy the reference type properties inside the object. Common ways to implement deep copy include:

  • By serializing and deserializing: serializing an object into a byte stream and then deserializing it into a new object creates a completely independent copy of the original object.
  • By copying reference type properties one by one: for each reference type property, create a new instance and copy the contents of the original object property into the new instance.

It should be noted that not all objects can be deep copied. Properties in some objects or classes may be immutable and do not need to be copied; some objects may contain circular references and cannot be fully copied. Therefore, when performing a cloning operation, it is necessary to select an appropriate copying method according to the specific situation.

The main difference between deep copy and shallow copy is the way to deal with internal reference type properties of objects.

  1. Depth of data replication hierarchy:

    • Shallow copy only copies the object itself and the properties of the basic data types inside the object, and does not recursively copy the properties of the reference type. Therefore, in a shallow copy, the new object and the original object share access to the same reference-type property.
    • In addition to copying the properties of the object itself and basic data types, deep copy also recursively copies the properties of the reference type inside the object. In this way, a deep copy creates a completely independent new object that has no connection to the original object.
  2. Association between objects:

    • The new object resulting from a shallow copy shares access to properties of the same reference type as the original object. If a reference type property is modified on one of the objects, the other object is also affected.
    • The new object obtained by deep copy has no relationship with the original object, and modifying the reference type attribute of one object will not affect the other object.
  3. Allocation of memory areas:

    • In a shallow copy, the new object and the original object point to the same memory area. Therefore, modifications to one object may affect the other.
    • In a deep copy, the new object and the original object correspond to different memory areas, and there is no reference relationship between them, so modifying one of the objects will not affect the other.

shallow copy example

Implement the Cloneable interface and override the clone() method:

  • The Cloneable interface in Java is a marker interface that does not define any methods. A shallow copy of an object can be achieved by implementing the Cloneable interface and overriding the clone() method.
  • In the clone() method, call the clone() method of the parent class and perform type conversion on the return value to complete the shallow copy.

Here is a sample code that demonstrates how to use the Cloneable interface and the clone() method to implement a shallow copy:

class Person implements Cloneable {
    
    
    private String name;
    private int age;

    public Person(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public int getAge() {
    
    
        return age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
    
    
        return super.clone();
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Person person1 = new Person("Alice", 25);
        try {
    
    
            // 浅拷贝
            Person person2 = (Person) person1.clone();

            System.out.println(person1.getName() + " " + person1.getAge()); // Alice 25
            System.out.println(person2.getName() + " " + person2.getAge()); // Alice 25

            person2.setName("Bob");
            person2.setAge(30);

            System.out.println(person1.getName() + " " + person1.getAge()); // Alice 25
            System.out.println(person2.getName() + " " + person2.getAge()); // Bob 30
        } catch (CloneNotSupportedException e) {
    
    
            e.printStackTrace();
        }
    }
}

In the above example, we created a Person class and implemented the Cloneable interface. In the clone() method, the clone() method of the parent class is directly called, and the type conversion is performed. By calling clone()the method, you can get a new object with the same property values person2​​as the original object . person1When modifying person2the properties of , it will not be affected person1.

Deep copy example

Use serialization and deserialization:

  • Write the object into the byte stream, and then read it out from the byte stream. This process will recreate a completely independent object and realize the deep copy.
  • In order to implement a deep copy, both the object and its associated objects need to be serialized.

Here is a sample code that demonstrates how to implement deep copy using serialization and deserialization:

import java.io.*;

class Address implements Serializable {
    
    
    private String city;
    private String street;

    public Address(String city, String street) {
    
    
        this.city = city;
        this.street = street;
    }

    public void setCity(String city) {
    
    
        this.city = city;
    }

    public void setStreet(String street) {
    
    
        this.street = street;
    }

    public String getCity() {
    
    
        return city;
    }

    public String getStreet() {
    
    
        return street;
    }
}

class Person implements Serializable {
    
    
    private String name;
    private int age;
    private Address address;

    public Person(String name, int age, Address address) {
    
    
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public void setAddress(Address address) {
    
    
        this.address = address;
    }

    public String getName() {
    
    
        return name;
    }

    public int getAge() {
    
    
        return age;
    }

    public Address getAddress() {
    
    
        return address;
    }
}

public class Main {
    
    
    public static void main(String[] args) {
    
    
        Address address = new Address("City", "Street");
        Person person1 = new Person("Alice", 25, address);

        // 深拷贝
        Person person2 = deepCopy(person1);

        System.out.println(person1.getName() + " " + person1.getAge() + " " + person1.getAddress().getCity()); // Alice 25 City
        System.out.println(person2.getName() + " " + person2.getAge() + " " + person2.getAddress().getCity()); // Alice 25 City

        person2.setName("Bob");
        person2.setAge(30);
        person2.getAddress().setCity("New City");

        System.out.println(person1.getName() + " " + person1.getAge() + " " + person1.getAddress().getCity()); // Alice 25 City
        System.out.println(person2.getName() + " " + person2.getAge() + " " + person2.getAddress().getCity()); // Bob 30 New City
    }

    public static <T extends Serializable> T deepCopy(T object) {
    
    
        try {
    
    
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(object);
            objectOutputStream.flush();
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            return (T) objectInputStream.readObject();
        } catch (IOException | ClassNotFoundException e) {
    
    
            e.printStackTrace();
            return null;
        }
    }
}

In the above example, we created an Address class and a Person class, both of which implement the Serializable interface. Through serialization and deserialization operations, we can achieve deep copy. In deepCopy()the method, we use the byte stream to write the object into memory and read it from memory, resulting in a new independent object. By calling deepCopy()the method, a new object can be obtained person2, which is person1completely independent from the original object. When modifying person2the properties of , it will not be affected person1.
It is worth noting that to implement deep copy, all related classes need to implement the Serializable interface.

The difference between deep copy and shallow copy

Deep Copy (Deep Copy):

  1. Applicable scene:

    • When the source object contains attributes of reference type, if you need to copy all the attributes of the object and its subobjects, not just copy the reference, you need to use deep copy.
    • When you want to modify the properties of the copied object without affecting the original object, you need to use deep copy.
  2. working principle:

    • Deep copy recursively copies the source object and all its associated objects. Each object has an independent memory space, and modifying the copy object will not affect the original object.
  3. Method to realize:

    • Use recursion or a copy constructor to copy properties of an object and its subobjects.
  4. Example scenario:

    • Make a copy of a complex object as an independent entity, e.g. copy a data structure containing collections, nested objects, etc.
    • Cloning of an object graph, when the original object contains sub-objects, and modifications to the sub-objects should not affect the original object.

Shallow Copy:

  1. Applicable scene:

    • When the properties of the source object are all basic data types or immutable objects, and there is no need to copy the properties of the reference type, shallow copy can be used.
    • Shallow copies are used when you want to modify the properties of the copied object while affecting the original object.
  2. working principle:

    • Shallow copy only copies the object and its reference, not the actual object pointed to by the reference, and the old and new objects will share the same referenced object. Modifications to the duplicate object affect the original object.
  3. Method to realize:

    • Usually use the object clone()method to make a shallow copy.
  4. Example scenario:

    • Quickly create copies of objects to modify them in certain operations while preserving the original.
    • In some cases, a portion of the data is shared to save memory and improve performance.

Guess you like

Origin blog.csdn.net/u012581020/article/details/132057664