Shallow Copy and Deep Copy in Java

Introduction

Shallow Copy also means Shallow Clone and Deep Copy also means Deep Clone.

Cloning an object is about creating the copy of the original object, i.e., making an identical copy of the original object.

By default, cloning in Java is field by field copy i.e. as the Object class does not have idea about the structure of class on which clone() method will be invoked. Therefore JVM does the following things when called for cloning:

  • If the class has only primitive data type members then a completely new copy of the object will be created and the reference to the newly copied object will be returned.
  • If the class contains members of any class or object type then only the object references to those members are copied and hence the member references in both the original object as well as the cloned object refer to the same object.

Let’s take an example, we want to copy object A and we get object B from that. Let’s see how it happens in shallow and in deep copy.

Shallow Copy or Clone

Shallow copy duplicates as little as possible. A shallow copy of a collection is a copy of the collection structure, not the elements. With a shallow copy, two collections now share the individual elements.

In shallow copy when we copy object A and B object is created. Object B points to the object A‘s location in the memory. So the reference pointer is copied just like the values. Therefore, the reference is pointing to the original object. Any changes to the member that are stored by reference appear in both the original and the copied object, since no copy was made of the referenced object.

A shallow copy or clone is similar to Call By Reference where both formal and actual parameters of a function refers to same memory location and the value.

Deep Copy or Clone

Deep copy duplicates everything. A deep copy of a collection is two collections with all of the elements in the original collection duplicated.

In deep copy when we copy object A then object B is created. All things in object A‘s memory location get copied to object B‘s memory location. So the pointer to object stored by reference is not copied. Instead, a deep copy is made of the referenced object, and a pointer to the new object is stored. Any changes that are made to those referenced object will not affect other copies of the object.

A deep copy is similar to Call By Value where both formal and actual parameters of a functions refers to different memory location but having the same value.

Examples

In Java, if a class needs to support cloning it has to do following things:

  • It must implement Cloneable interface.
  • It must override clone() method from Object class.

Shallow Copy or Clone

Create two simple POJO classes.

package com.roytuts.java.shallow.deep.clone.copy;

public class Employee {

	private String name;

	public Employee(String name) {
		this.name = name;
	}

	//getters and setters

}

The below POJO class implements cloneable interface.

package com.roytuts.java.shallow.deep.clone.copy;

public class Department implements Cloneable {

	private String name;
	private Employee employee;

	public Department(String name, Employee employee) {
		this.name = name;
		this.employee = employee;
	}

	public String getName() {
		return name;
	}

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

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}

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

}

Test Class

We create a class with main method to test our shallow copy or clone.

package com.roytuts.java.shallow.deep.clone.copy;

public class ShallowCloneTest {

	public static void main(String[] args) throws CloneNotSupportedException {
		Employee employee = new Employee("Soumitra");
		Department department = new Department("Computer", employee);

		Department clonedDept = (Department) department.clone();

		System.out.println("Employee name in department : " + department.getEmployee().getName());
		System.out.println("Employee name in clonedDept : " + clonedDept.getEmployee().getName());

		System.out.println();
		System.out.println("After setting Employee name to cloned object");
		System.out.println();

		clonedDept.getEmployee().setName("Soumitra2");

		System.out.println("After setting, Employee name in clonedDept : " + clonedDept.getEmployee().getName());
		System.out.println("After setting, Employee name in department : " + department.getEmployee().getName());
	}

}

Testing the Program

Employee name in department : Soumitra
Employee name in clonedDept : Soumitra

After setting Employee name to cloned object

After setting, Employee name in clonedDept : Soumitra2
After setting, Employee name in department : Soumitra2

In the above output we see that after setting the new Employee name to the cloned object, the original object gets affected.

Deep Copy or Clone

Now in deep copy our Employee class will also implement Cloneable interface and override the clone() method.

package com.roytuts.java.shallow.deep.clone.copy;

public class Employee implements Cloneable {

	private String name;

	public Employee(String name) {
		this.name = name;
	}

	//getters and setters

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

Department class has to modify its clone() method as below:.

package com.roytuts.java.shallow.deep.clone.copy;

public class Department implements Cloneable {

	private String name;
	private Employee employee;

	public Department(String name, Employee employee) {
		this.name = name;
		this.employee = employee;
	}

	public String getName() {
		return name;
	}

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

	//getters and setters

	@Override
	public Object clone() throws CloneNotSupportedException {
		Department d = (Department) super.clone();
		d.setEmployee((Employee) d.getEmployee().clone());

		return d;
	}

}

Test Class

Write a test program to test the program:

package com.roytuts.java.shallow.deep.clone.copy;

public class DeepCloneTest {

	public static void main(String[] args) throws CloneNotSupportedException {
		Employee employee = new Employee("Soumitra");
		Department department = new Department("Computer", employee);

		Department clonedDept = (Department) department.clone();

		System.out.println("Employee name in department : " + department.getEmployee().getName());
		System.out.println("Employee name in clonedDept : " + clonedDept.getEmployee().getName());

		System.out.println();
		System.out.println("After setting Employee name to cloned object");
		System.out.println();

		clonedDept.getEmployee().setName("Soumitra2");

		System.out.println("After setting, Employee name in clonedDept : " + clonedDept.getEmployee().getName());
		System.out.println("After setting, Employee name in department : " + department.getEmployee().getName());
	}

}

Testing the Program

Employee name in department : Soumitra
Employee name in clonedDept : Soumitra

After setting Employee name to cloned object

After setting, Employee name in clonedDept : Soumitra2
After setting, Employee name in department : Soumitra

In the above output we see that after setting the new Employee name to the cloned object the original object does not get affected.

That’s all. Thanks for reading.

Leave a Reply

Your email address will not be published. Required fields are marked *