Before we start learning about deep and shallow cloning, let’s look at the following code. Any questions?
class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
// Assign equals (base type)
int number = 6;
int number2 = number;
// Change the value of number2
number2 = 9;
System.out.println("number:" + number);
System.out.println("number2:" + number2);
// Assign the equals sign (object)
Dog dog = new Dog();
dog.name = "Prosperous wealth.";
dog.age = 5;
Dog dog2 = dog;
// Change the dog2 value
dog2.name = "Rhubarb";
dog2.age = 3;
System.out.println(dog.name + "," + dog.age + "Age");
System.out.println(dog2.name + "," + dog2.age + "Age"); }}Copy the code
Program execution result:
Number:6Number2:9Rhubarb,3At the age of rhubarb,3At the age ofCopy the code
As can be seen, when using equal sign copy, for value types, the modification operations are relatively independent of each other. For reference types, because the memory address of the reference object is copied, the modification of one value will also change the other value, as shown in the following figure:
First, shallow clone
The default shallow clone implementation method is clone(), the implementation code is as follows:
class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Dog dog = new Dog();
dog.name = "Prosperous wealth."; dog.age = 5; // Clone Dog dog3 = (Dog) dog.clone(); dog3.name ="White";
dog3.age = 2;
System.out.println(dog.name + "," + dog.age + "Age");
System.out.println(dog3.name + "," + dog3.age + "Age");
}
}
class Dog implements Cloneable {
public String name;
public int age;
@Override
protected Object clone() throws CloneNotSupportedException {
returnsuper.clone(); }}Copy the code
Program execution result:
Wang CAI, 5, Xiao Bai, 2Copy the code
As you can see, cloning can be used to solve the problem of reference type replication, as shown in the following figure:
Shallow clone.
Implementation conditions of shallow clone:The objects to be cloned must be implementedCloneable
Interface, rewriteclone()
Method, can be implemented to clone the object. However,There is also a problem with using shallow clones
class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
DogChild dogChild = new DogChild();
dogChild.name = "The dog";
Dog dog4 = new Dog();
dog4.name = "Rhubarb";
dog4.dogChild = dogChild;
Dog dog5 = (Dog) dog4.clone();
dog5.name = "Prosperous wealth.";
dog5.dogChild.name = "Dog.";
System.out.println("dog name 4:"+dog4.name);
System.out.println("dog name 5:"+dog5.name);
System.out.println("dog child name 4:"+dog4.dogChild.name);
System.out.println("dog child name 5:"+dog5.dogChild.name);
}
}
class Dog implements Cloneable {
public String name;
public DogChild dogChild;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class DogChild {
public String name;
}
Copy the code
Program execution result:
Dog name 4: Rhubarb dog name 5: Prosperous fortune dog Child name 4: Dog child name 5: Dog twoCopy the code
In other words, shallow clone will copy only the value type of the object, but not the reference type of the object. The reasons are as follows:
A deep clone
Second, deep cloning
Definition: A deep clone copies the entire object information, including value types and reference types. Procloning is usually implemented in the following two ways.
- Serialization to implement deep clone: first serialize the original object to the byte stream in memory, and then deserialize the stored object from the byte stream. The new object and the original object do not share any address, so as to achieve deep clone.
- Clone all reference types: All reference types of objects to be copied are cloned, and all objects are new objects to be copied, thus implementing deep cloning.
Deep clone implementation method 1: serialization
Implementation idea: first copy object will be written to the byte stream in memory, and then read from the byte stream just stored information, as a new object, then the new object and the original object does not have any address sharing, natural implementation of deep copy. Please refer to the following code:
class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
BirdChild birdChild = new BirdChild();
birdChild.name = "Little bird";
Bird bird = new Bird();
bird.name = "The bird"; bird.birdChild = birdChild; Clone (Bird) with Bird bird2 = cloneutils.clone (Bird); bird2.name ="Yellowbird";
bird2.birdChild.name = "Little yellow sparrow";
System.out.println("bird name:" + bird.name);
System.out.println("bird child name:" + bird.birdChild.name);
System.out.println("bird name 2:" + bird2.name);
System.out.println("bird child name 2:" + bird2.birdChild.name);
}
}
class CloneUtils {
public static <T extends Serializable> T clone(T obj) {
T cloneObj = null; Try {// Write ByteArrayOutputStream bo = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bo); oos.writeObject(obj); oos.close(); ByteArrayInputStream bi = new ByteArrayInputStream(bo.tobyteArray ()); ObjectInputStream oi = new ObjectInputStream(bi); // Returns the generated new objectcloneObj = (T) oi.readObject();
oi.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj; }}Copy the code
Program execution result:
The bird name is the bird child nameCopy the code
Deep clone implementation method 2: All reference types are cloned
class SerializableTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ParrotChild parrotChild = new ParrotChild();
parrotChild.name = "Parakeet";
Parrot parrot = new Parrot();
parrot.name = "Big Parrot"; parrot.parrotChild = parrotChild; Parrot parrot2 = (Parrot) parrot.clone(); parrot2.name ="Old Parrot";
parrot2.parrotChild.name = "Young Parrot";
System.out.println("parrot name:" + parrot.name);
System.out.println("parrot child name:" + parrot.parrotChild.name);
System.out.println("parrot name 2:" + parrot2.name);
System.out.println("parrot child name 2:" + parrot2.parrotChild.name);
}
}
class Parrot implements Cloneable {
public String name;
public ParrotChild parrotChild;
@Override
protected Object clone() throws CloneNotSupportedException {
Parrot bird = (Parrot) super.clone();
bird.parrotChild = (ParrotChild) parrotChild.clone();
return bird;
}
}
class ParrotChild implements Cloneable {
public String name;
@Override
protected Object clone() throws CloneNotSupportedException {
returnsuper.clone(); }}Copy the code
Program execution result:
Parrot's name is Parrot Child nameCopy the code
3. Cloning related interview questions
1. What are the benefits of using cloning?
A: The benefits include the following:
- Easy to use: if you want to copy an object, but part of the attributes of the object has been modified, if you do not use cloning, you need to manually assign the attributes, compared to cloning is a lot of trouble;
- High performance: It can be seen from the Clone method that it is a native method. Native method is a native function and is implemented by the language at the bottom of the operating system, so the execution efficiency is higher.
- Isolation: Cloning ensures that objects operate in isolation from each other.
Clone () source code, as shown below:
2. What is the difference between shallow cloning and deep cloning?
A: The difference is mainly in the copying of reference types. Details are as follows:
- Shallow clone: Only the value type of the object is copied, but not the reference type of the object.
- Deep clone: Copies the entire object, including value types and reference types.
3. How to implement shallow clone?
A: Clone objects implement the Cloneable interface, and rewrite the Clone () method to implement shallow clones.
4. What is the result of the following code execution?
import java.util.Arrays;
class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
CloneObj cloneObj = new CloneObj();
cloneObj.name = "Wang";
cloneObj.age = 30;
cloneObj.sistersAge = new int[]{18, 19};
CloneObj cloneObj2 = (CloneObj) cloneObj.clone();
cloneObj2.name = "Leilei";
cloneObj2.age = 33;
cloneObj2.sistersAge[0] = 20;
System.out.println(cloneObj.name + "|" + cloneObj2.name);
System.out.println(cloneObj.age + "|" + cloneObj2.age);
System.out.println(Arrays.toString(cloneObj.sistersAge) + "|" + Arrays.toString(cloneObj2.sistersAge));
}
}
class CloneObj implements Cloneable {
public String name;
public int age;
public int[] sistersAge;
@Override
protected Object clone() throws CloneNotSupportedException {
returnsuper.clone(); }}Copy the code
A: The result is as follows.
Lao wang | leilei 33 [20, 19] | | 30 [20, 19]Copy the code
5. How is deep cloning implemented? How many ways are there to do that?
A: There are two general implementation methods:
- Deep clone through serialization (serialization implementation: Java native serialization, JSON serialization, Hessian serialization);
- All reference types are cloned, thereby implementing deep cloning.
6. Why can’t Clone the Object method directly, but need to rewrite the Clone () method to achieve cloning?
A: Although all classes are subclasses of Object, because the clone() method in Object is declared protected access, other classes that are not part of the java.lang package cannot be used directly. To implement cloning, you must implement Cloneable and override the clone() method.
7. Can serialization achieve deep cloning? What is the implementation principle?
A: The original object is serialized to the byte stream in memory, and then the newly stored object is deserialized from the byte stream. The new object and the original object do not share any address, thus realizing the deep clone.
Four,
The clone() method in Object is a shallow clone by default. Shallow clones can only copy value types, not reference types. Therefore, more scenarios require deep clones.
Click here to download the source of this article
Special note: This article is from the “Java interview question full analysis”