DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality
  • Addressing Memory Issues and Optimizing Code for Efficiency: Glide Case
  • Singleton: 6 Ways To Write and Use in Java Programming

Trending

  • Building a Real-Time Change Data Capture Pipeline With Debezium, Kafka, and PostgreSQL
  • Web Crawling for RAG With Crawl4AI
  • Enhancing Business Decision-Making Through Advanced Data Visualization Techniques
  • Can You Run a MariaDB Cluster on a $150 Kubernetes Lab? I Gave It a Shot
  1. DZone
  2. Coding
  3. Languages
  4. Shallow vs. Deep Copy in Java

Shallow vs. Deep Copy in Java

Take a look at this in-depth explanation of the differences and uses for Shallow and Deep copies in Java.

By 
Marcus Biel user avatar
Marcus Biel
·
Updated Apr. 04, 17 · Tutorial
Likes (25)
Comment
Save
Tweet
Share
211.0K Views

Join the DZone community and get the full member experience.

Join For Free

In this article from my free Java 8 Course, I will be discussing the difference between a Deep and a Shallow Copy. You can download the slides and the article as PDF here.


What Is a Copy?

To begin, I’d like to highlight what a copy in Java is. First, let’s differentiate between a reference copy and an object copy. A reference copy, as the name implies, creates a copy of a reference variable pointing to an object. If we have a Car object, with a myCar variable pointing to it and we make a reference copy, we will now have two myCar variables, but still one object.

Image title

Example 1

An object copy creates a copy of the object itself. So if we again copied our car object, we would create a copy of the object itself, as well as a second reference variable referencing that copied object.

Image title

Example 2

What Is an Object?

Both a Deep Copy and a Shallow Copy are types of object copies, but what really is an object? Often, when we talk about an object, we speak of it as a single unit that can’t be broken down further, like a humble coffee bean. However, that’s oversimplified.

Image title

Example 3

Say we have a Person object. Our Person object is in fact composed of other objects, as you can see in Example 4. Our Person contains a Name object and an Address object. The Name in turn, contains a FirstName and a LastName object; the Address object is composed of a Street object and a City object. So when I talk about Person in this article, I’m actually talking about this entire network of objects.

Image title

Example 4

So why would we want to copy this Person object? An object copy, usually called a clone, is created if we want to modify or move an object, while still preserving the original object. There are many different ways to copy an object that you can learn about in another article. In this article we’ll specifically be using a copy constructor to create our copies.

Shallow Copy

First let’s talk about the shallow copy. A shallow copy of an object copies the ‘main’ object, but doesn’t copy the inner objects. The ‘inner objects’ are shared between the original object and its copy. For example, in our Person object, we would create a second Person, but both objects would share the same Name and Address objects.

Let’s look at a coding example. In Example 5, we have our class Person, which contains a Name and Address object. The copy constructor takes the originalPerson object and copies its reference variables.

public class Person {
    private Name name;
    private Address address;

    public Person(Person originalPerson) {
         this.name = originalPerson.name;
         this.address = originalPerson.address;
    }
[…]
}

Example 5

The problem with the shallow copy is that the two objects are not independent. If you modify the Name object of one Person, the change will be reflected in the other Person object.

Let’s apply this to an example. Say we have a Person object with a reference variable mother; then, we make a copy of mother, creating a second Person object, son. If later on in the code, the son tries to moveOut() by modifying his Address object, the mother moves with him!

Person mother = new Person(new Name(…), new Address(…));
[…]
Person son  = new Person(mother);
[…]
son.moveOut(new Street(…), new City(…));

Example 6

This occurs because our mother and son objects share the same Address object, as you can see illustrated in Example 7. When we change the Address in one object, it changes in both!

Image title

Example 7

Deep Copy

Unlike the shallow copy, a deep copy is a fully independent copy of an object. If we copied our Person object, we would copy the entire object structure.

Image title

Example 8

A change in the Address object of one Person wouldn’t be reflected in the other object as you can see by the diagram in Example 8. If we take a look at the code in example 9, you can see that we’re not only using a copy constructor on our Person object, but we are also utilizing copy constructors on the inner objects as well.

public class Person {
    private Name name;
    private Address address;

    public Person(Person otherPerson) {
         this.name    =  new Name(otherPerson.name);
         this.address =  new Address(otherPerson.address);
    }
[…]
}

Example 9

Using this deep copy, we can retry the mother-son example from Example 6. Now the son is able to successfully move out!

However, that’s not the end of the story. To create a true deep copy, we need to keep copying all of the Person object’s nested elements, until there are only primitive types and “Immutables” left. Let’s look at the Street class to better illustrate this:

public class Street {
    private String name;
    private int number;

    public Street(Street otherStreet){
         this.name = otherStreet.name;
         this.number = otherStreet.number;
    }
[…]
}

Example 10

The Street object is composed of two instance variables – String name and int number. int number is a primitive value and not an object. It’s just a simple value that can’t be shared, so by creating a second instance variable, we are automatically creating an independent copy. String is an Immutable. In short, an Immutable is an Object, that, once created, can never be changed again. Therefore, you can share it without having to create a deep copy of it.

Conclusion

To conclude, I’d like to talk about some coding techniques we used in our mother-son example. Just because a deep copy will let you change the internal details of an object, such as the Address object, it doesn’t mean that you should. Doing so would decrease code quality, as it would make the Person class more fragile to changes – whenever the Address class is changed, you will have to (potentially) apply changes to the Person class also. For example, if the Address class no longer contains a Street object, we’d have to change the moveOut() method in the Person class on top of the changes we already made to the Address class.

In Example 6 of this article I only chose to use a new Street and City object to better illustrate the difference between a shallow and a deep copy. Instead, I would recommend that you assign a new Address object instead, effectively converting to a hybrid of a shallow and a deep copy, as you can see in Example 10:

Person mother = new Person(new Name(…), new Address(…));
[…]
Person son  = new Person(mother);
[…]
son.moveOut(new Address(...));

Example 11

In object-oriented terms, this violates encapsulation, and therefore should be avoided. Encapsulation is one of the most important aspects of Object Oriented programming. In this case, I had violated encapsulation by accessing the internal details of the Address object in our Person class. This harms our code because we have now entangled the Person class in the Address class and if we make changes to the Address class down the line, it could harm the Person class as I explained above. While you obviously need to interconnect your various classes to have a coding project, whenever you connect two classes, you need to analyze the costs and benefits.

Object (computer science) Java (programming language)

Published at DZone with permission of Marcus Biel, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality
  • Addressing Memory Issues and Optimizing Code for Efficiency: Glide Case
  • Singleton: 6 Ways To Write and Use in Java Programming

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!