Java clone object – cloning in java

Filed Under: Java

Today we will look into java clone object or cloning in java. Java Object class comes with native clone() method that returns the copy of the existing instance.

Java clone object

java clone object, cloning in java
To use java object clone() method, we have to implement the marker interface java.lang.Cloneable so that it won’t throw CloneNotSupportedException at runtime. Also Object clone is a protected method, so we will have to override it to use with other classes.

Let’s look at this with an example.


package com.journaldev.cloning;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class Employee implements Cloneable {

	private int id;

	private String name;

	private Map<String, String> props;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

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

	public Map<String, String> getProps() {
		return props;
	}

	public void setProps(Map<String, String> p) {
		this.props = p;
	}

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

}

Notice that we are using Object clone() implementation, so we have to implement Cloneable interface.

Let’s test our java clone object example with a simple program.


package com.journaldev.cloning;

import java.util.HashMap;
import java.util.Map;

public class CloningTest {

	public static void main(String[] args) throws CloneNotSupportedException {

		Employee emp = new Employee();

		emp.setId(1);
		emp.setName("Pankaj");
		Map<String, String> props = new HashMap<>();
		props.put("salary", "10000");
		props.put("city", "Bangalore");
		emp.setProps(props);

		Employee clonedEmp = (Employee) emp.clone();

		// Check whether the emp and clonedEmp attributes are same or different
		System.out.println("emp and clonedEmp == test: " + (emp == clonedEmp));
		
		System.out.println("emp and clonedEmp HashMap == test: " + (emp.getProps() == clonedEmp.getProps()));
		
		// Let's see the effect of using default cloning
		
		// change emp props
		emp.getProps().put("title", "CEO");
		emp.getProps().put("city", "New York");
		System.out.println("clonedEmp props:" + clonedEmp.getProps());

		// change emp name
		emp.setName("new");
		System.out.println("clonedEmp name:" + clonedEmp.getName());

	}

}

Above cloning will produce the following output.


emp and clonedEmp == test: false
emp and clonedEmp HashMap == test: true
clonedEmp props:{city=New York, salary=10000, title=CEO}
clonedEmp name:Pankaj

If our Employee class won’t implement Cloneable interface, above program will throw java.lang.CloneNotSupportedException runtime exception.


Exception in thread "main" java.lang.CloneNotSupportedException: com.journaldev.cloning.Employee
	at java.lang.Object.clone(Native Method)
	at com.journaldev.cloning.Employee.clone(Employee.java:41)
	at com.journaldev.cloning.CloningTest.main(CloningTest.java:19)

java clone object, java CloneNotSupportedException

Let’s look into the first output and understand what’s happening with Object clone() method and if there is an issue with it.

  1. emp and clonedEmp == test: false

    So emp and clonedEmp are two different objects, not referring to the same object. This is in agreement with the java clone object requirement.

  2. emp and clonedEmp HashMap == test: true

    So both emp and clonedEmp object variables refer to the same object. This comes with a serious problem with cloning, we will see that next.

  3. clonedEmp props:{city=New York, salary=10000, title=CEO}

    Notice that we didn’t make any change in clonedEmp properties, but still, they got changed because both emp and clonedEmp variables are referring to the same object.

    This is a serious problem because default cloning in java doesn’t create totally detached objects. This can lead to unwanted results, hence the need to properly override the java clone object method.

  4. clonedEmp name:Pankaj

    What happened here?

    We changed the emp name but clonedEmp name didn’t change. It’s because String is immutable. So when we are setting emp name, a new string is created and emp name reference is changed in this.name = name;.

    Hence clonedEmp name remains unchanged. You will find similar behavior for any primitive variable types too. So we are good with java clone object default method as long as we have only primitive and immutable variables in the object.

Shallow Cloning

Default implementation of java clone object is using shallow copy, something like below using reflection.


@Override
 public Object clone() throws CloneNotSupportedException {
 
	 Employee e = new Employee();
	 e.setId(this.id);
	 e.setName(this.name);
	 e.setProps(this.props);
	 return e;
}

Deep Cloning

In deep cloning, we have to copy fields one by one. We can override the clone method like below for deep cloning.


public Object clone() throws CloneNotSupportedException {

	Object obj = super.clone(); //utilize clone Object method

	Employee emp = (Employee) obj;

	// deep cloning for immutable fields
	emp.setProps(null);
	Map<String, String> hm = new HashMap<>();
	String key;
	Iterator<String> it = this.props.keySet().iterator();
	// Deep Copy of field by field
	while (it.hasNext()) {
		key = it.next();
		hm.put(key, this.props.get(key));
	}
	emp.setProps(hm);
	
	return emp;
}

With this clone method, our test program will produce the following output.


emp and clonedEmp == test: false
emp and clonedEmp HashMap == test: false
clonedEmp props:{city=Bangalore, salary=10000}
clonedEmp name:Pankaj

This is what we want, the clone() method should return a new object totally detached from the original.

So if you are thinking to use Object clone and cloning in your program, do it wisely and override it properly by taking care of immutable instances.

Note that it could be a daunting task if your class extends other class that in turn extending other class and so on. You will have to go all the way to take care of the deep copy of all the immutable fields.

Cloning using Serialization

One way to easily perform deep cloning is through serialization. But serialization is an expensive procedure and your class should implement Serializable interface.

Cloning in java using Apache Commons Util

If you are already using Apache Commons Util classes in your project and your class is serializable, then use the below method.


Employee clonedEmp = org.apache.commons.lang3.SerializationUtils.clone(emp);

Copy Constructor for Cloning

We can also define a copy constructor and get a copy of the object and don’t depend on the cloning at all.

For example, we can have Employee constructor like below.


public Employee(Employee emp) {
	
	this.setId(emp.getId());
	this.setName(emp.getName());
	
	Map<String, String> hm = new HashMap<>();
	String key;
	Iterator<String> it = emp.getProps().keySet().iterator();
	// Deep Copy of field by field
	while (it.hasNext()) {
		key = it.next();
		hm.put(key, emp.getProps().get(key));
	}
	this.setProps(hm);

}

Whenever we need a copy of employee object, we can get it using Employee clonedEmp = new Employee(emp);.

However writing copy constructor can be a tedious job if your class has a lot of variables, especially primitive and immutable.

Java clone object best practices

  1. Use default Object clone() method only when your class has primitives and immutable variables. Note that this applies for with inheritance too. You will have to check all the classes you are extending till the Object level.
  2. You can also define copy constructor if your class mostly consists of mutable objects.
  3. Utilize Object clone() method by calling super.clone() in overridden clone method, then make necessary changes for deep copying mutable fields.
  4. If your class is serializable, you can use serialization too for cloning. However, it will come with a performance hit, so do some benchmarking before using this method for cloning.
  5. If you are extending a class and it has defined clone method properly using deep copy, then you can utilize default clone method. For example, we have properly defined clone() method in Employee class as below.
    
    package com.journaldev.cloning;
    
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    public class Employee implements Cloneable {
    
    	private int id;
    
    	private String name;
    
    	private Map<String, String> props;
    
    	public int getId() {
    		return id;
    	}
    
    	public void setId(int id) {
    		this.id = id;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public Map<String, String> getProps() {
    		return props;
    	}
    
    	public void setProps(Map<String, String> p) {
    		this.props = p;
    	}
    
    	@Override
    	public Object clone() throws CloneNotSupportedException {
    
    		Object obj = super.clone();
    
    		Employee emp = (Employee) obj;
    
    		// deep cloning for immutable fields
    		emp.setProps(null);
    		Map<String, String> hm = new HashMap<>();
    		String key;
    		Iterator<String> it = this.props.keySet().iterator();
    		// Deep Copy of field by field
    		while (it.hasNext()) {
    			key = it.next();
    			hm.put(key, this.props.get(key));
    		}
    		emp.setProps(hm);
    
    		return emp;
    	}
    
    }
    

    We can have a child class like below.

    
    package com.journaldev.cloning;
    
    public class EmployeeWrap extends Employee implements Cloneable {
    
    	private String title;
    
    	public String getTitle() {
    		return title;
    	}
    
    	public void setTitle(String t) {
    		this.title = t;
    	}
    
    	@Override
    	public Object clone() throws CloneNotSupportedException {
    
    		return super.clone();
    	}
    }
    

    Notice that EmployeeWrap doesn’t have any mutable properties and it’s utilizing super class clone() method implementation.

    Here is a simple program to test if this way of cloning works fine or not.

    
    package com.journaldev.cloning;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class CloningTest {
    
    	public static void main(String[] args) throws CloneNotSupportedException {
    
    		EmployeeWrap empWrap = new EmployeeWrap();
    
    		empWrap.setId(1);
    		empWrap.setName("Pankaj");
    		empWrap.setTitle("CEO");
    		
    		Map<String, String> props = new HashMap<>();
    		props.put("salary", "10000");
    		props.put("city", "Bangalore");
    		empWrap.setProps(props);
    
    		EmployeeWrap clonedEmpWrap = (EmployeeWrap) empWrap.clone();
    		
    		empWrap.getProps().put("1", "1");
    		
    		System.out.println("empWrap mutable property value = "+empWrap.getProps());
    
    		System.out.println("clonedEmpWrap mutable property value = "+clonedEmpWrap.getProps());
    		
    	}
    
    }
    

    Output produced is:

    
    empWrap mutable property value = {1=1, city=Bangalore, salary=10000}
    clonedEmpWrap mutable property value = {city=Bangalore, salary=10000}
    

    So it worked perfectly as we expected.

That’s all about java clone object or cloning in java. I hope you got some idea about Object clone method and how to properly override it without any adverse effect.

You can download the project from my GitHub Repository.

Reference: API Doc for Object clone

Comments

  1. knpcode says:

    Object cloning in Java is the easiest way to get a new object with a state. You don’t need to go through the whole process of calling new operator to create an object and assign value to its fields.

  2. Prakash says:

    In case of HashMap where we have immutable Key and immutable value.
    We do not need to do deep cloning explicitly.

    HashMap override Object clone() method, which will take care of providing functionality of deep cloning.

    1. Shabd says:

      HI Pankaj,

      Thanks for wonderful article.You been of great help always.
      Coming to question if HashMap key/value is immutable then why we are doing deep cloning here?

      1. Pankaj says:

        HashMap keys should be immutable for its proper functioning. It’s not a requirement.

  3. Arun SIngh says:

    thanks

  4. Anil Gupta From Sidhi Mp says:

    thanks alot

  5. Elhanan Maayan says:

    please note that are deep clone frameworks such as beanlib (which can even clone instrumented hibernate classes) so that you won’t have to write boiler plate code.

  6. Tran Nam says:

    Great, I got it. Thanks for your post 🙂

  7. suhasini says:

    Hi Pankaj,
    when i run this class as it is in eclipse using open-jdk-6, it gives me second output
    and i did not understand one thing,after cloning setting new values on actual object obviously differ from the cloned object right ?

    1. Pankaj says:

      First of all thanks for executing the program. I forgot to comment the clone() method while publishing. I have commented it now.
      Second thing is that when we use default cloning, it just copies the reference of the object that is clear from boolean output of ct1.getProps() == ct2.getProps(). So to avoid any changes getting reflected from one object to other its necessary to provide our own implementation of clone method.

Leave a Reply

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

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages