Wednesday, March 15, 2023

Shallow Copy And Deep Copy in Java Object Cloning

In this post we’ll see what are shallow copy and deep copy in Java with respect to Java object cloning and what are the differences between shallow copy and deep copy in Java.

Object cloning in Java

Object cloning is the process of creating an exact copy of the existing object. When you clone an object you get a new instance with the same content for the fields in the new object as in existing object.

Object cloning in Java is done using clone() method which is defined in java.lang.Object class. Only those object that implement Cloneable interface are eligible for cloning.

Both shallow copy and deep copy relates to how object is cloned. When object cloning is done using the default clone method (by calling the clone method of the Object class) it returns a shallow copy of the object.

For creating a deep copy of an object you would need to override the clone method.


Shallow copy in Java

As already stated when you use default clone() method, shallow copy of the object is created. What it means is that there would be field-to-field assignment. New object will also have the same fields as the original object and the same content for the fields too. It works fine for primitive data types but in case there is another object reference in your class it may be a problem.

If a class whose object is cloned contains another object then field-to-field assignment will be done for the contained object too in the cloning process. Since Java is pass by value, so copying the value of the object means object reference would be copied and there lies the problem.

Reference of the contained object is shared between the original object and the cloned object and making any change to that object in the cloned object would be reflected in the original object too and vice versa is also true.

For example suppose there is a class ClassB which has another object objA of Class A.
public class ClassB implements Cloneable{
  private ClassA objA;
  ...
  ...
}

When object of ClassB is cloned, objA reference is shared between the original object and the cloned object.

Shallow copy in Java
Shallow copy

Shallow copy Java example

Here we have a Class called ClassA with 2 int fields. Another class ClassB which has a ClassA object and an int field.

Then you create an object objB of ClassB and clone it to get a new object objB2. In both of these objects, reference of ClassA object will be shared.

ClassA

public class ClassA implements Cloneable{
 private int i;
 private int j;
 // Constructor
 public ClassA(int i, int j){
  this.i = i;
  this.j = j;
 }
 public void setI(int i) {
  this.i = i;
 }
 public void setJ(int j) {
  this.j = j;
 }
 public int getI() {
  return i;
 }
 public int getJ() {
  return j;
 }
}

ClassB

public class ClassB implements Cloneable{
 private int x;
 private ClassA objA;
 
 public ClassB(int x, ClassA objA){
  this.x = x;
  this.objA = objA;
 }
 public Object clone() throws CloneNotSupportedException{
  return super.clone();
 }
 public int getX() {
  return x;
 }
 public ClassA getObjA() {
  return objA;
 }
 public void setX(int x) {
  this.x = x;
 }
 public void setObjA(ClassA objA) {
  this.objA = objA;
 }
}

CloningDemo class

public class CloningDemo {

 public static void main(String[] args) {
  ClassB objB = new ClassB(10, new ClassA(20, 30));
  
  ClassB objB2 = null;
  try {
   objB2 = (ClassB)objB.clone();
   
  } catch (CloneNotSupportedException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  // value of field i of objA changed 
  // in cloned object
  objB2.getObjA().setI(100); 
  // Value of primitive field x changed 
  // in cloned object
  objB2.setX(1);
  System.out.println("objB.x- " +  objB.getX() + " objB.objA.i- " + objB.getObjA().getI() + " objB.objA.j- " + objB.getObjA().getJ());

  System.out.println("objB2.x- " +  objB2.getX() + " objB2.objA.i- " + objB2.getObjA().getI() + " objB2.objA.j- " + objB2.getObjA().getJ());

 }
}

Output

objB.x- 10 objB.objA.i- 100 objB.objA.j- 30
objB2.x- 1 objB2.objA.i- 100 objB2.objA.j- 30 

In CloningDemo class objB is cloned to get a new instance objB2. Value of primitive field x is changed in the cloned object objB2, you can see that both objects have their own independent values for field x.

Coming to object field, objB2 will have its own field objA where value of field i is changed. You can see that value in the original object objB for objA.i is also changed as the objA reference is shared between the objects. That’s one drawback of shallow copy.

Deep Copy in Java

When a deep copy is done objects referenced by the cloned object are distinct from those referenced by original object, and independent.

To create a deep copy while cloning an object you need to override clone method and call clone() method for even the objects referenced by the cloned object.

Deep copies are more expensive, as you need to create additional objects, and can be substantially more complicated, due to references possibly forming a complicated graph.

Deep copy Java example

Here we have a Class called ClassA with 2 int fields. Another class ClassB which has a ClassA object and an int field.

In classB, clone() method is overridden and clone method is explicitly called for the reference object objA too to get a separate copy of referenced object too.

class ClassA implements Cloneable{
  private int i;
  private int j;
  // Constructor
  public ClassA(int i, int j){
   this.i = i;
   this.j = j;
  }
  public void setI(int i) {
   this.i = i;
  }
  public void setJ(int j) {
   this.j = j;
  }
  public int getI() {
   return i;
  }
  public int getJ() {
   return j;
  }
  public Object clone() throws CloneNotSupportedException{
   return super.clone();
  }
}

class ClassB implements Cloneable{
  private int x;
  private ClassA objA;
  
  public ClassB(int x, ClassA objA){
   this.x = x;
   this.objA = objA;
  }
  public Object clone() throws CloneNotSupportedException{
   ClassB obj =  (ClassB) super.clone();
   // explicitly cloning classA object too
   obj.objA = (ClassA) objA.clone();
   return obj;
  }
  public int getX() {
   return x;
  }
  public ClassA getObjA() {
   return objA;
  }
  public void setX(int x) {
   this.x = x;
  }
  public void setObjA(ClassA objA) {
   this.objA = objA;
  }
}

public class CloningDemo {

 public static void main(String[] args) {
   ClassB objB = new ClassB(10, new ClassA(20, 30));
   
   ClassB objB2 = null;
   try {
    objB2 = (ClassB)objB.clone();
    
   } catch (CloneNotSupportedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
   // value of field i of objA changed 
   // in cloned object
   objB2.getObjA().setI(100); 
   // Value of primitive field x changed 
   // in cloned object
   objB2.setX(1);
   System.out.println("objB.x- " +  objB.getX() + " objB.objA.i- " + objB.getObjA().getI() + " objB.objA.j- " + objB.getObjA().getJ());

   System.out.println("objB2.x- " +  objB2.getX() + " objB2.objA.i- " + objB2.getObjA().getI() + " objB2.objA.j- " + objB2.getObjA().getJ());

  }
}

Output

objB.x- 10 objB.objA.i- 20 objB.objA.j- 30
objB2.x- 1 objB2.objA.i- 100 objB2.objA.j- 30

Now the change to objA.i field in the cloned object is not reflected to the original object.

Shallow copy Vs Deep Copy in Java

  1. In case of shallow copy, primitive fields are created separately for the cloned object but any object reference is shared between the original and cloned object.
    In case of deep copy, separate copies of the referenced objects are also created so that original and cloned object are completely independent of each other.
  2. If class has only primitive fields shallow copy is the best choice.
    If class contains other objects then you need deep copy to have separate copies for the contained objects.
  3. Object cloning done by using Object class’ clone() method by default creates a shallow copy of an object.
    For creating a deep copy of any object you need to override the clone() method and provide the functionality to create separate copies of the reference objects too.
  4. Shallow copies are simple to implement and typically cheap, as they can be usually implemented by simply copying the bits exactly.
    Deep copies are expensive and more complicated because you may have to create a whole object graph for the cloned object.

That's all for this topic Shallow Copy And Deep Copy in Java Object Cloning. If you have any doubt or any suggestions to make please drop a comment. Thanks!

>>>Return to Java Basics Tutorial Page


Related Topics

  1. Serialization and Deserialization in Java
  2. Nested Class And Inner Class in Java
  3. How to Pass Command Line Arguments in Eclipse
  4. Difference Between equals() Method And equality Operator == in Java
  5. BigDecimal in Java With Examples

You may also like-

  1. Just In Time Compiler (JIT) in Java
  2. Inter-thread Communication Using wait(), notify() And notifyAll() in Java
  3. AtomicInteger in Java With Examples
  4. HashMap Vs LinkedHashMap Vs TreeMap in Java
  5. EnumSet in Java With Examples
  6. Java Program to Find The Longest Palindrome in a Given String
  7. Spring Web MVC Tutorial
  8. Installing Hadoop on a Single Node Cluster in Pseudo-Distributed Mode

1 comment: