• Skip to main content
  • Skip to secondary menu
  • Skip to primary sidebar
  • Skip to footer
  • Home
  • Contact Us

All about code

  • Java
    • Spring
      • Spring Boot
      • Spring Cloud
    • Java Miscellaneous Tips
    • Java Design Patterns
  • Data Structures and Algorithms
    • Algorithms
    • Data Structures
  • Thoughts and Stories
  • AI

How to Create a Deep or a Shallow Copy in Java

coffee cup and saucer beverage tea 24961

Introduction

Copying a Java object means creating a new class instance with the same state as the original object. The state can be replicated in two different ways: by making a shallow copy or a deep copy. In this article, we will discuss the meaning and implications of this.

Difference Between Primitive and Reference Types in the Copy Operation

A Java class can contain both primitive and reference variables as attributes. A variable of primitive type contains an actual raw value, set to a default if not explicitly assigned, and stored in Java Stack memory. A variable of a reference type, on the other hand, can contain a reference to an object stored in Heap memory or a null value. We can also call a reference-type attribute of a class a dependency of that class.

If we copy the value of a primitive variable A into a separate variable B, B will have its own copy of the value. So, if we change the value in B, A will retain its original value.

If A and B are of a reference type, after the copy, B will contain a reference to the same object referenced by A.

2.1. Shallow Copy

In a shallow copy, we copy the primitive attributes of the object plus its reference-type ones, i.e., its dependencies. In this scenario, the state of the correspondent dependencies is shared between the original and copied objects (they both point to the same dependency object).

2.2. Deep Copy

In a deep copy, we make a shallow copy of the object plus a shallow copy of each dependency (and of the dependencies of each dependency if needed). In this case, the correspondent dependencies in the original object and the copied instance will have their own independent states.

Shallow and Deep Copy Implementation

To implement a shallow copy, we can override the protected clone method of the Object class by making it public. The Object‘s clone method performs a shallow copy. It’s also necessary to implement the Cloneable marker interface to avoid a CloneNotSupportedException.

For a deep copy, we must repeat the clone operation for the dependencies using a specific method (deepClone in our example). To simplify the example, we consider a class Main with a single attribute called Dependency:

public class Main implements Cloneable {
	private Dependency dependency;
	 	
	public Main(Dependency dependency) {
		super();
		this.dependency = dependency;
	}

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

	public Object deepClone() throws CloneNotSupportedException {
		Main dependentClone = (Main) super.clone();
		Dependency dependencyClone = (Dependency) this.dependency.clone();
		dependentClone.setDependency(dependencyClone);
		return dependentClone;
	}
	
	public Dependency getDependency() {
		return dependency;
	}

	public void setDependency(Dependency dependency) {
		this.dependency = dependency;
	}
	
}
public class Dependency implements Cloneable {
	private int value = 13;
	
	public Dependency(int value) {
		super();
		this.value = value;
	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}

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

We can use unit tests to verify the behavior in the two scenarios:

@Test
public void givenAnObjectAndADependency_whenShallowClonedAndDepencyChanges_ThenDepencyHasNewValue() throws Exception {
    Dependency dependency = new Dependency(13);
    Main main = new Main(dependency);
    Main shallowClone = (Main) main.clone();
    dependency.setValue(17);
    assertEquals(17, shallowClone.getDependency()
        .getValue());
}
@Test
public void givenAnObjectAndADependency_whenDeepClonedAndDepencyChanges_ThenDepencyKeepsOldValue() throws Exception {
    Dependency dependency = new Dependency(13);
    Main main = new Main(dependency);
    Main deepClone = (Main) main.deepClone();
    dependency.setValue(17);
    assertEquals(13, deepClone.getDependency()
        .getValue());
}

In the shallow copy scenario, the dependency value of the copied object contains the last set value, which is 17. In the deep copy, the 13 value is returned instead. This is because the dependency has been copied as well, and its state with it.

Conclusion

In this article, we have seen how the state of the objects is handled in a shallow or deep copy scenario. The example code is available on GitHub.

Primary Sidebar

Social

  • Facebook
  • LinkedIn
  • Twitter

Archives

  • May 2026
  • April 2026
  • March 2026
  • August 2025
  • July 2025
  • June 2025
  • May 2025
  • April 2025
  • March 2025
  • December 2024
  • October 2024
  • August 2024
  • July 2024
  • March 2024
  • February 2024
  • January 2024
  • December 2023
  • September 2023
  • May 2023
  • March 2023
  • January 2023
  • November 2022
  • September 2022
  • August 2022

Recent Posts

  • Better Avoid Spring Boot Lazy-initialization @PostConstruct Trap
  • How To Handle Large Datasets in Spring Boot
  • How to Log HTTP Incoming Requests in Spring Boot
  • How to Reliably Implement Post-Commit Actions in Spring
  • Brief and Easy Explanation of HATEOAS

TAGS

Algorithms Apache POI Backtracking Date Structures Dynamic Programming engineering Graphs Greedy Horror Stories HSSF Java Java New Features Java Principles Java tips real life Sorting Spring Boot Spring Cloud Strings Trees

Footer

Privacy Policy Cookie Policy Terms and Conditions