Shallow Copy And Deep Copy In Java

Shallow Copy/Deep Copy

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, you want to copy object A and you 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 you 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 you 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 – Shallow And Deep Copy

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.

public class Employee {

	private String name;

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

	//getters and setters

}

The below POJO class implements cloneable interface.

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();
	}

}

Shallow Copy Test Class

I have created a class with main method to test our shallow copy or clone.

public class ShallowCopyCloneTest {

	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, you 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.

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:.

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;
	}

}

Deep Copy Test Class

Write a test program to test the program:

public class DeepCopyCloneTest {

	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, you see that after setting the new Employee name to the cloned object the original object does not get affected.

Source Code

Download

Leave a Reply

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