How to deep clone an object in Java

  • 25 July 2017
  • ADM

 

How to deep clone an object in Java - images/logos/java.jpg

 

In this article will present how to deep clone an object. This is required when the variables from the object are other objects or lists. What actually happens if the deep cloning technique is not applied? The child object that is not cloned will actually be the same in both parent objects.

To see how to clone a simple (shallow) object check How to clone an object in Java tutorial.

Example

In order to see how deep clone needs to be implemented will create 2 classes: User and Address. The User class will have an Adress object. Both classes need to implements Cloneable Interface.

User.java

The import part is happening in the clone method where each object needs to be cloned separately and added to the cloned parent object.

package com.admfactory.clone;

public class User implements Cloneable {
    private String name;
    private String email;
    private int age;
    private Address address;

    public String getName() {
	return name;
    }

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

    public String getEmail() {
	return email;
    }

    public void setEmail(String email) {
	this.email = email;
    }

    public int getAge() {
	return age;
    }

    public void setAge(int age) {
	this.age = age;
    }

    public Address getAddress() {
	return address;
    }

    public void setAddress(Address address) {
	this.address = address;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
	User user;
	try {
	    user = (User) super.clone();
	    if (address != null)
		user.address = (Address) address.clone();
	} catch (CloneNotSupportedException e) { // this should never happen
	    System.out.println("CloneNotSupportedException thrown " + e);
	    return null;
	}
	return user;
    }

    @Override
    public String toString() {
	String result = "name: " + name + ", email: " + email + ", age: " + age;
	if (address != null)
	    result += ", address: " + address;
	return result;
    }
}

Address.java

package com.admfactory.clone;

public class Address implements Cloneable {
    private String street;
    private String city;
    private int number;

    public String getStreet() {
	return street;
    }

    public void setStreet(String street) {
	this.street = street;
    }

    public String getCity() {
	return city;
    }

    public void setCity(String city) {
	this.city = city;
    }

    public int getNumber() {
	return number;
    }

    public void setNumber(int number) {
	this.number = number;
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
	try {
	    return super.clone();
	} catch (CloneNotSupportedException e) {
	    System.out.println("CloneNotSupportedException thrown " + e);
	    throw new CloneNotSupportedException();
	}
    }

    @Override
    public String toString() {
	return number + " " + street + ", " + city;
    }

}

Usage

package com.admfactory.clone;

public class DeepCloneExample {
    public static void main(String[] args) throws CloneNotSupportedException {
	System.out.println("Object deep cloning example");
	System.out.println();

	/** defining one object */
	User user1 = new User();
	user1.setName("John Doe");
	user1.setEmail("john@example.com");
	user1.setAge(100);
	Address address1 = new Address();
	address1.setCity("London");
	address1.setNumber(91);
	address1.setStreet("Lambard");
	user1.setAddress(address1);

	System.out.println("User 1: ");
	System.out.println(user1.toString());
	System.out.println();

	/**
	 * cloning the object - Notice the cast as the clone method from Cloneable
	 * returns Object
	 */
	User user2 = (User) user1.clone();
	System.out.println("User 2: ");
	System.out.println(user2.toString());
	System.out.println();
	/** changing the address for user 1 */
	Address address2 = user1.getAddress();
	address2.setCity("Glasgow");
	address2.setNumber(12);
	address2.setStreet("Peter");
	user1.setAddress(address2);

	System.out.println("User 1: ");
	System.out.println(user1.toString());
	System.out.println();

	System.out.println("User 2: ");
	System.out.println(user2.toString());
	System.out.println();
    }
}

Output

Object deep cloning example

User 1: 
name: John Doe, email: john@example.com, age: 100, address: 91 Lambard, London

User 2: 
name: John Doe, email: john@example.com, age: 100, address: 91 Lambard, London

User 1: 
name: John Doe, email: john@example.com, age: 100, address: 12 Peter, Glasgow

User 2: 
name: John Doe, email: john@example.com, age: 100, address: 91 Lambard, London

You can notice that changing the address object from the user1 object is not affecting the address object from the user2 object. In order to see the difference, you can comment the line 46-47 from User.java and run again the test application. You can see from the output that changing the address object from user1 is affecting the address object from user2, actually is the same object assigned to both user objects.

 

References