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

  • High-Performance Java Serialization to Different Formats
  • Did You Know the Fastest Way of Serializing a Java Field Is Not Serializing It at All?
  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality

Trending

  • Efficient API Communication With Spring WebClient
  • Introducing Graph Concepts in Java With Eclipse JNoSQL
  • How To Introduce a New API Quickly Using Quarkus and ChatGPT
  • Building a Real-Time Audio Transcription System With OpenAI’s Realtime API
  1. DZone
  2. Coding
  3. Languages
  4. How to Deep Clone an Object Using Java In-Memory Serialization

How to Deep Clone an Object Using Java In-Memory Serialization

Check out this post in a series on Java cloning and serialization.

By 
Naresh Joshi user avatar
Naresh Joshi
DZone Core CORE ·
Aug. 21, 19 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
13.0K Views

Join the DZone community and get the full member experience.

Join For Free

In my previous articles, I explained the difference between deep and shallow cloning and how copy-constructors and defensive copy methods are better than default Java cloning.

Java object cloning using copy constructors and defensive copy methods certainly have some advantages but we have to explicitly write some code to achieve deep cloning in all these approaches. And still, there are chances that we might miss something and do not get a deeply cloned object.

As discussed in this article: Five Different Ways to Create Objects in Java, deserializing a serialized object creates a new object with the same state as in the serialized object. So similar to the above cloning approaches, we can achieve deep cloning functionality using object serialization and deserialization as well, and with this approach, we do not have worry about or write code for deep cloning — we get it by default.

However, cloning an object using serialization comes with some performance overhead. We can improve on it by using in-memory serialization. If we just need to clone the object and don't need to persist it in a file for future use.

We will use below Employee class as an example, which has name, doj, and skills as the state. For deep cloning, we do not need to worry about the code>name field because it is a String object, and by default, all strings are immutable in nature.

You can read more about immutability in  How to Create an Immutable Class in Java and Why String is Immutable and Final.
class Employee implements Serializable {
    private static final long serialVersionUID = 2L;

    private String name;
    private LocalDate doj;
    private List<String> skills;

    public Employee(String name, LocalDate doj, List<String> skills) {
        this.name = name;
        this.doj = doj;
        this.skills = skills;
    }

    public String getName() { return name; }
    public LocalDate getDoj() { return doj; }
    public List<String> getSkills() { return skills; }

    // Method to deep clone a object using in memory serialization
    public Employee deepClone() throws IOException, ClassNotFoundException {
        // First serializing the object and its state to memory using ByteArrayOutputStream instead of FileOutputStream.
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(bos);
        out.writeObject(this);

        // And then deserializing it from memory using ByteArrayOutputStream instead of FileInputStream.
        // Deserialization process will create a new object with the same state as in the serialized object,
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream in = new ObjectInputStream(bis);
        return (Employee) in.readObject();
    }

    @Override
    public String toString() {
        return String.format("Employee{name='%s', doj=%s, skills=%s}", name, doj, skills);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Employee employee = (Employee) o;

        return Objects.equals(name, employee.name) &&
            Objects.equals(doj, employee.doj) &&
            Objects.equals(skills, employee.skills);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, doj, skills);
    }
}


To deep clone an object of Employee class, I have provided a deepClone() method, which serializes the object to memory by using ByteArrayOutputStream instead of the FileOutputStream and deserializes it back using ByteArrayInputStream instead of the FileInputStream. Here, we are serializing the object into bytes and deserializing it from bytes to object again.

Employee class implements Serializable interface to achieve serialization, which has its own disadvantages, and we can overcome some of these disadvantages by customizing the serialization process by using Externalizable interface.

We can run the below tests to see if our cloning approach is deep or just shallow; here, all == operations will return false (because both objects are separate) and all equals will return true (because both have the same content).

public static void main(String[] args) throws IOException, ClassNotFoundException {
 Employee emp = new Employee("Naresh Joshi", LocalDate.now(), Arrays.asList("Java", "Scala", "Spring"));
 System.out.println("Employee object: " + emp);

 // Deep cloning `emp` object by using our `deepClone` method.
 Employee clonedEmp = emp.deepClone();
 System.out.println("Cloned employee object: " + clonedEmp);

 System.out.println();

 // All of this will print false because both objects are separate.
 System.out.println(emp == clonedEmp);
 System.out.println(emp.getDoj() == clonedEmp.getDoj());
 System.out.println(emp.getSkills() == clonedEmp.getSkills());

 System.out.println();

 // All of this will print true because `clonedEmp` is a deep clone of `emp` and both have the same content.
 System.out.println(Objects.equals(emp, clonedEmp));
 System.out.println(Objects.equals(emp.getDoj(), clonedEmp.getDoj()));
 System.out.println(Objects.equals(emp.getSkills(), clonedEmp.getSkills()));
}


We know the deserialization process creates a new object every time, which is not good if we have to make our class singleton. And that's why we need to override and disable serialization for our singleton class, which we can achieve by providing writeReplace and readResolve methods.

Similar to serialization, Java cloning also does not play along with singleton pattern, and that's why we need to override and disable it as well. We can do that by implementing cloning in a way that it will either throw CloneNotSupportedException or return the same instance every time.

You can find the complete source code for this article on this GitHub repository. Please feel free to provide your valuable feedback in the comments section!

Object (computer science) Serialization Java (programming language) Clone (Java method) Cloning

Published at DZone with permission of Naresh Joshi, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • High-Performance Java Serialization to Different Formats
  • Did You Know the Fastest Way of Serializing a Java Field Is Not Serializing It at All?
  • Writing DTOs With Java8, Lombok, and Java14+
  • Redefining Java Object Equality

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!