Introduction to deep copy of deep copy and shallow copy of shallow copy in Java

  • 2020-04-01 03:47:48
  • OfStack

Deep copy (deep copy) and shallow copy (shallow copy) are two common concepts, especially in the C++ language, that can cause problems with delete if you don't understand them, but fortunately we're using Java here. Although Java automatically manages object recycling, we need to pay enough attention to deep (deep) and shallow (shallow) copies because sometimes these two concepts can cause us a lot of confusion.

A shallow copy is one that copies only the object itself (including the basic variables in the object), but not the object to which the reference contained in the object refers. Deep copy copies not only the object itself, but all the objects to which it contains references. For example, it's clearer: object A1 contains a reference to B1, and B1 contains a reference to C1. A shallow copy of A1 gives you A2, which still contains a reference to B1, which still contains a reference to C1. The deep copy is a recurrence of the shallow copy. The deep copy A1 gets A2, which contains a reference to B2 (copy of B1), and B2 to C2 (copy of C1).

If the clone() method is not overwritten, the resulting object is a shallow copy. Let's focus on the deep copy.

Run the following program and take a look at the shallow copy:


class Professor0 implements Cloneable { 
  String name; 
  int age; 
 
  Professor0(String name, int age) { 
    this.name = name; 
    this.age = age; 
  } 
 
  public Object clone() throws CloneNotSupportedException { 
    return super.clone(); 
  } 
} 
 
class Student0 implements Cloneable { 
  String name;//Constant object.
  int age; 
  Professor0 p;//Student 1 and student 2 both have the same reference value.
 
  Student0(String name, int age, Professor0 p) { 
    this.name = name; 
    this.age = age; 
    this.p = p; 
  } 
 
  public Object clone() { 
    Student0 o = null; 
    try { 
      o = (Student0) super.clone(); 
    } catch (CloneNotSupportedException e) { 
      System.out.println(e.toString()); 
    } 
 
    return o; 
  } 
} 
 
public class ShallowCopy { 
  public static void main(String[] args) { 
    Professor0 p = new Professor0("wangwu", 50); 
    Student0 s1 = new Student0("zhangsan", 18, p); 
    Student0 s2 = (Student0) s1.clone(); 
    s2.p.name = "lisi"; 
    s2.p.age = 30; 
    s2.name = "z"; 
    s2.age = 45; 
    System.out.println(" students s1 Name: " + s1.name + "n students s1 Name of professor: " + s1.p.name + "," + "n students s1 Professor's age " + s1.p.age);//Student 1's professor
  } 
}

S2 is changed, but s1 is also changed, proving that p of s1 and p of s2 point to the same object. This is not the case in the actual requirements we have, so we need a deep copy:


class Professor implements Cloneable { 
  String name; 
  int age; 
 
  Professor(String name, int age) { 
    this.name = name; 
    this.age = age; 
  } 
 
  public Object clone() { 
    Object o = null; 
    try { 
      o = super.clone(); 
    } catch (CloneNotSupportedException e) { 
      System.out.println(e.toString()); 
    } 
    return o; 
  } 
} 
 
class Student implements Cloneable { 
  String name; 
  int age; 
  Professor p; 
 
  Student(String name, int age, Professor p) { 
    this.name = name; 
    this.age = age; 
    this.p = p; 
  } 
 
  public Object clone() { 
    Student o = null; 
    try { 
      o = (Student) super.clone(); 
    } catch (CloneNotSupportedException e) { 
      System.out.println(e.toString()); 
    } 
    o.p = (Professor) p.clone(); 
    return o; 
  } 
} 
 
public class DeepCopy { 
  public static void main(String args[]) { 
    long t1 = System.currentTimeMillis(); 
    Professor p = new Professor("wangwu", 50); 
    Student s1 = new Student("zhangsan", 18, p); 
    Student s2 = (Student) s1.clone(); 
    s2.p.name = "lisi"; 
    s2.p.age = 30; 
    System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age);//Student 1's professor does not change.
    long t2 = System.currentTimeMillis(); 
    System.out.println(t2-t1); 
  } 
}

Of course, we also have a deep copy method, which is to serialize objects:


import java.io.*; 
//Serialization is time-consuming 
class Professor2 implements Serializable { 
  
  private static final long serialVersionUID = 1L; 
  String name; 
  int age; 
 
  Professor2(String name, int age) { 
    this.name = name; 
    this.age = age; 
  } 
} 
 
class Student2 implements Serializable { 
  
  private static final long serialVersionUID = 1L; 
  String name;//Constant object.
  int age; 
  Professor2 p;//Student 1 and student 2 both have the same reference value.
 
  Student2(String name, int age, Professor2 p) { 
    this.name = name; 
    this.age = age; 
    this.p = p; 
  } 
 
  public Object deepClone() throws IOException, OptionalDataException, 
      ClassNotFoundException { 
    //Write the object to the stream
    ByteArrayOutputStream bo = new ByteArrayOutputStream(); 
    ObjectOutputStream oo = new ObjectOutputStream(bo); 
    oo.writeObject(this); 
    //Read it out of the stream
    ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray()); 
    ObjectInputStream oi = new ObjectInputStream(bi); 
    return (oi.readObject()); 
  } 
 
} 
 
public class DeepCopy2 { 
 
  
  public static void main(String[] args) throws OptionalDataException, 
      IOException, ClassNotFoundException { 
    long t1 = System.currentTimeMillis(); 
    Professor2 p = new Professor2("wangwu", 50); 
    Student2 s1 = new Student2("zhangsan", 18, p); 
    Student2 s2 = (Student2) s1.deepClone(); 
    s2.p.name = "lisi"; 
    s2.p.age = 30; 
    System.out.println("name=" + s1.p.name + "," + "age=" + s1.p.age); //Student 1's professor does not change.
    long t2 = System.currentTimeMillis(); 
    System.out.println(t2-t1); 
  } 
 
}

However, serialization is time-consuming. In some frameworks, we can feel that they tend to pass objects after serialization, which takes a lot of time.


Related articles: