English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

java Deep Copy and Shallow Copy Mechanism Detailed Explanation

 java Deep Copy and Shallow Copy Mechanism Detailed Explanation

Summary:

In Java, copying is divided into shallow copy and deep copy. Java implements a method called clone in the public superclass Object, and the new object cloned by this method is a shallow copy, while the deep copy is through the clone method defined by oneself.

(1) clone method in Object

If we create a new object, refer to it with a declaration, and then use another declaration to refer to the previous declaration, then the final result is: the two declarations of the variables will point to the same object, and they will all be changed if one is changed. If we want to create a copy of an object, and this copy is completely the same as the object's various properties, and modifying this copy has nothing to do with the original object, then at this time we need to use the clone method.

package Clone;
import java.util.Date;
/**
 * 
 * @author QuinnNorris 
 * Two copy mechanisms in Java
 */
public class Clone {
  /**
   * @param args
   * @throws CloneNotSupportedException 
   */
  public static void main(String[] args) throws CloneNotSupportedException {
    // TODO Auto-generated method stub
    ClassA valA = new ClassA(1, "old", new Date());
    // Declare a new ClassA object, we don't need to pay too much attention to the functionality of ClassA
    ClassA valB = valA;
    // Assign the object referenced by valA to valB
    valA.setObject("new");
    // Modify the value in valA, and at this time valB is also modified, because valA and valB point to the same object
    valB = valA.clone();//Create a copy through the clone method
  }
}

The part of ClassA's clone method rewritten:

//It is necessary to implement the Cloneable interface
public class ClassA implements Cloneable {
  public ClassA clone() throws CloneNotSupportedException {
    return (ClassA) super.clone();//Call the clone method of the superclass (Object)
  }
}

1. How to use the clone method in Object

Someone summarized four rules for using the clone method, let's share them together:

  1. To obtain a copy of the object, we can use the clone() method of the Object class.
  2. Override the clone() method of the base class in the derived class and declare it as public.
  3. In the clone() method of the derived class, call super.clone().
  4. Implement the Cloneable interface in the derived class.

 2. The clone method with protected modification

In java.lang.Object, it sets the clone method to protected, which is a very special case. The scope of protected is: package visibility+. Inheritable. The reason for this setting is that the method needs to return the cloned object, that is, the type to be cloned by the clone method is unknown, there is no way to determine the type of the return value, so it can only be implemented by the descendants and can be overwritten. In order to allow descendants to inherit and not be too open, it is set to protected type.

3. Implementing the clone method requires implementing the Cloneable interface

Why do we implement the Cloneable interface when we override the clone method? In fact, the Cloneable interface is a marker interface in Java, which is an interface without methods and properties. They exist only to let people know some information, and can be used for judgment when: xxx instanceof Cloneable. The appearance of this interface is to let the designer know that cloning needs to be processed. If an object needs to be cloned but does not implement (in fact, 'implement' can be replaced with 'write' more accurately) the Cloneable interface, then a checked exception will occur.

4. Implementing the clone method requires calling the clone of the superclass

In order to achieve the purpose of creating an object that is exactly the same as the one that calls the method, we need to use the clone method of the superclass, and the superclass goes the same way until it reaches the clone method of Object, then what is the use of the clone method of Object? The API says this:

protected Object clone() throws CloneNotSupportedException
to create and return a copy of this object.
The accurate meaning of 'copy' may depend on the class of the object. The purpose of doing so is, for any object x,
The expression: x.clone() != x is also true,
The expression: x.clone().getClass() == x.getClass() is also true,
But these are not mandatory requirements.
Generally speaking:
x.clone().equals(x) is true, but this is not a mandatory requirement.
By convention, the returned object should be obtained by calling super.clone().
If a class and all of its superclasses (except Object) adhere to this convention, then x.clone().getClass() == x.getClass().

That's a basic explanation of clone in the API. We can conclude that as long as super.clone() is called reasonably, it will return a cloned object. At runtime, Object's clone() identifies which object you want to copy, allocates space for it, and copies the object, copying the content of the original object one by one into the storage space of the new object. In this cloned object, all properties are the same as the properties of the object to be cloned, and these same properties are divided into two types:

First type: The eight primitive types and immutable objects (such as String)
Second type: Other class objects

For the first type, the clone method sets their values to the values of the original object, which is no problem. For the second type, the clone method simply points the reference of the copied new object to the reference pointed to by the original object, and the second type of class object will be modified by two objects. At this point, it involves the concept of deep and shallow copy.

(2) Shallow copy

Shallow copy: All variables of the copied object contain the same values as the original object, and all references to other objects still point to the original object. In other words, shallow copy only copies the object under consideration, but does not copy the objects it references.

For example, if class A has a variable of type class B, when A overrides the clone function and calls super.clone, the new object created and the class B type variable in the original object are the same, and they point to the same type variable of B. If you make a modification to the B variable in A, the B variable in the newly copied object will also be modified in the same way.
Remember that all clone methods implemented by direct calls to super.clone are shallow copies.

(3) Deep copy

Deep copy: All variables of the copied object contain the same values as the original object, except for those variables that reference other objects. Those variables that reference other objects will point to the newly copied objects, rather than the original referenced objects. In other words, deep copy copies all the objects referenced by the object to be copied.

In simple terms, if it is a shallow copy, at the beginning there are two lines, and if there is another class variable at the end, the two lines will merge into one at the end, pointing to this variable together, and both can operate on it. Deep copy is completely two lines, with no interference, because it has copied all the objects of the internal variables.

In the code for deep copy, it is necessary to write multiple calls to the clone function of other classes in this class in the clone method.

(4) Serialization deep copy

In some frameworks, we sometimes find that there is no override of the clone method, so how do we operate when we need to copy an object? The answer is that we often use serialization methods, implementing the Serializable interface.

There is no choice but to look for other methods to replace deep copy, if you adopt the traditional deep copy, wouldn't you have to copy all the object variables by chasing through countless layers when copying an object? Not to mention the time consumption of doing so, just writing such code would be daunting. Serialization deep copy is such a relatively simple method.

The process of writing an object to a stream is known as serialization (Serilization) process, but in the Java programmer's circle, it is also very vividly called the 'freezing' or 'pickling' process; while the parallelization (Deserialization) process of reading an object from the stream is called 'unfreezing' or 'restoring (depicking)' process. It should be pointed out that what is written to the stream is a copy of the object, and the original object still exists in the JVM, so what is pickled is just a copy of the object, and Java pickled objects can be restored.

This is a professional explanation on the internet, and I won't attempt to improve upon it. In Java, to perform a deep copy of an object, it is often necessary to first make the object implement the Serializable interface, then write the object (which is actually just a copy of the object) to a stream (preserving it as pickled), and then read it back from the stream (restoring it from pickled) to reconstruct the object.

public Object deepClone() 
{ 
 //Write object 
 ByteArrayOutputStream bo = new ByteArrayOutputStream(); 
 ObjectOutputStream oo = new ObjectOutputStream(bo); 
 oo.writeObject(this); 
 //Read object
 ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); 
 ObjectInputStream oi = new ObjectInputStream(bi); 
 return(oi.readObject()); 
}

Although this academic code looks very complex, it is actually just putting the object into the stream and taking it out. Compared with analyzing and judging countless clones, this is extremely simple. The premise of doing this is that the object and all objects referenced internally by the object are serializable, otherwise, it is necessary to carefully examine whether the non-serializable objects are set to transient.

transient: Once an object implements the Serilizable interface, this object can be serialized (serialization refers to writing java code in the form of a byte sequence, that is, the three lines of code above write the object). This kind of serialization mode provided by Java to developers provides many conveniences, so that they do not need to be concerned about the specific serialization process, as long as the class implements the Serilizable interface, all properties and methods of this class will be automatically serialized. However, there is a situation where some properties do not need to be serialized, so this keyword is used. It only needs to implement the Serilizable interface, add the keyword transient before the property that does not need to be serialized, and this property will not be serialized to the specified destination when serializing the object.

(V) Summary

In practical applications, deep copy and shallow copy are just two concepts, and it is not necessarily better than the other. It should be determined according to the actual work on how to copy an object. If it is necessary to use shallow copy in database operations to extract a table without involving other tables, it is definitely necessary. In the framework's Serializable, although it takes time, deep copy is very necessary.

 Thank you for reading and hope it can help everyone. Thank you for your support of this site!

Statement: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been edited by humans, and does not assume any relevant legal responsibility. If you find any content suspected of copyright infringement, please send an email to: notice#oldtoolbag.com (When reporting, please replace # with @) for complaints, and provide relevant evidence. Once verified, this site will immediately delete the infringing content.

You May Also Like