How do you create immutable object in Java?

Most frequently asked interview question, when you say you have very good knowledge in Java. Below are similar questions:

Can you create an user defined immutable object?

How the class String is immutable?

 

What is immutable object?

An immutable object is an instance whose state never changes once they t is initialized. Example of an immutable class in Java is String.

 

How can we create immutable object?

Below are the mandatory condition for an instance to behave like an immutable object:

  • The class must be final, so that other classes cannot extend it.
  • Declare all the fields i.e., both static and instance variables with private as access specifier. This will not allow user to access the fields.
  • Don't provide setter method for the fields of the class.
  • Make all the mutable fields final, so that their value cannot be changed once they are initialized.
  • Initialize all the fields using Constructor only, that too using Deep Copy.
  • Perform Deep copy of the object and return from getter methods instead of returning the original object.

Below is the code which demonstrates how to create an immutable object by using above rules and what happens if we don't use deep copy and cloning in an immutable object.

 

This is an immutable class which uses deep copy initialization which initializing the class variable and also while returning the element it uses cloning, it never returns the original object so that we can't modify it anyways.

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

final class ImmutableClass {

private final HashMap<Integer,String> hashMap;

public ImmutableClass( HashMap<Integer,String> hashMap){
//Deep copy initialization
HashMap<Integer,String> newMap=new HashMap<Integer,String>();
Integer key;
Iterator<Integer> it = hashMap.keySet().iterator();
while(it.hasNext()){
key=it.next();
newMap.put(key, hashMap.get(key));
}
this.hashMap=newMap;
}
public HashMap<Integer, String> getHashMap() {
//Returning cloned object instead of original
return (HashMap<Integer, String>) hashMap.clone();
}
}

 

This another immutable object which doesn't use any deep copy mechanism or cloning.

final class Immutable1{
private final HashMap<Integer,String> hashMap;

public Immutable1(HashMap<Integer,String> hashMap){
this.hashMap=hashMap;
}

public HashMap<Integer, String> getHashMap() {
return this.hashMap;
}
}

 

This is driver class from which the execution starts. In the main method of this class we have initialized an HashMap and put some pairs in it. After that we have initialized the immutable object that uses deep copy mechanism and cloning. We have extracted to get the HashMap which is supplied to Immutable object and changed it locally  by putting a new key, value pair. Again we took the same HashMap from the same immutable object and printed it, found that there is no change if we change HashMap locally.

 

After that we have initialized the other immutable object which doesn't use the deep copy mechanism and cloning. We have taken the HashMap out of the immutable object and changed it locally by putting a new key,value pair. Again we have taken the same HashMap from the same immutable object found that the new key value pair added to the HashMap.

 

So the conclusion is, if we don't deep copy and cloning we can't achieve full immutability for an object.

public class ImmutableDemo{

public static void main(String[] args) {
HashMap<Integer, String> hashMap = new HashMap<Integer,String>();
hashMap.put(1234, "Employee1");
hashMap.put(2345, "Employee2");

//Immutable that uses deep copy and returns cloned object instead of original
System.out.println("Immutable class using deep copy and cloning");
ImmutableClass ic = new ImmutableClass( hashMap);
hashMap = ic.getHashMap();
System.out.println("HashMap before changing it locally: "+hashMap);

hashMap.put(3456, "Employee3");
hashMap = ic.getHashMap();
System.out.println("HashMap after changing it locally: "+hashMap);

//Immutable class which doesn't use deep copy
System.out.println("\n\nImmutable class without using deep copy and cloning");
Immutable1 ic1 = new Immutable1(hashMap);
hashMap = ic1.getHashMap();
System.out.println("HashMap before changing it locally: "+hashMap);

hashMap.put(9087, "Employee789");
hashMap = ic1.getHashMap();
System.out.println("HashMap after changing it locally: "+hashMap);

}
}

Output

Leave a Reply

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