Immutable Class in Java

Here i am going to share some questions on Immutable classes in java –

      1. What is an immutable class?

Immutable class is a class which once created, it’s contents can not be changed.  It means any modification on immutable object will result in a new immutable object. Immutable objects are particularly useful in concurrent applications. Since they cannot change state, they cannot be corrupted by thread interference or observed in an inconsistent state.

Example: String , Integer , Float etc.

      2.  How can you create custom immutable class in java?

  • Declare all instance variables private and final : 
    If you make instance variable private, no outside class will be able to access instance variables and if you make them final, you can not change it.
  • Don’t provide setter methods :
    Don’t create setter method for any instance variables, hence there will be no explicit way to change state of instance variables.
  • Initialize all variables in constructor :
    You can initialize variables in constructor. You need to take special care while working with mutable object. You need to do deep copy in case of immutable objects.
  • Make your class final : 
    If you make your class final, no class will be able to extend it, hence will not be able override methods of this class.
  • Clone mutable objects while returning from getter method:
    If you return clone of object from getter method, it won’t return original object, so your original object will remain intact. If the getters return an Object reference such as Collections, Arrays or other class object, clone the object before returning. Make sure the object is deep clone and not shallow.

FinalClassDemo.java

/**
Mutable class example
*
*/
package com.myjavablog.javainterview;

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

public final class FinalClassDemo {

private final int id;

private final String name;

private final HashMap<String, String> testMap;

public int getId() {
return id;
}

public String getName() {
return name;
}

/**
* Accessor function for mutable objects
*/
public HashMap<String, String> getTestMap() {
// return testMap;
return (HashMap<String, String>) testMap.clone();
}

/**
* Constructor performing Deep Copy
*
* @param i
* @param n
* @param hm
*/

public FinalClassDemo(int i, String n, HashMap<String, String> hm) {
System.out.println("Performing Deep Copy for Object initialization");
this.id = i;
this.name = n;
HashMap<String, String> tempMap = new HashMap<String, String>();
String key;
Iterator<String> it = hm.keySet().iterator();
while (it.hasNext()) {
key = it.next();
tempMap.put(key, hm.get(key));
}
this.testMap = tempMap;
}

/**
* Constructor performing Shallow Copy
*
* @param i
* @param n
* @param hm
*/
/**
* public FinalClassDemo(int i, String n, HashMap<String,String> hm){
* System.out.println("Performing Shallow Copy for Object initialization");
* this.id=i; this.name=n; this.testMap=hm; }
*/

/**
* To test the consequences of Shallow Copy and how to avoid it with Deep Copy
* for creating immutable classes
*
* @param args
*/
public static void main(String[] args) {
HashMap<String, String> h1 = new HashMap<String, String>();
h1.put("1", "Final1");
h1.put("2", "Final2");

String s = "original";

int i = 10;

FinalClassDemo ce = new FinalClassDemo(i, s, h1);

// Lets see whether its copy by field or reference
System.out.println(s == ce.getName());
System.out.println(h1 == ce.getTestMap());
// print the ce values
System.out.println("ce id:" + ce.getId());
System.out.println("ce name:" + ce.getName());
System.out.println("ce testMap:" + ce.getTestMap());
// change the local variable values
i = 20;
s = "modified";
h1.put("3", "Final3");
// print the values again
System.out.println("ce id after local variable change:" + ce.getId());
System.out.println("ce name after local variable change:" + ce.getName());
System.out.println("ce testMap after local variable change:" + ce.getTestMap());

HashMap<String, String> hmTest = ce.getTestMap();
hmTest.put("4", "Final4");

System.out.println("ce testMap after changing variable from accessor methods:" + ce.getTestMap());

}

}

     3. What is Deep Copy vs Shallow Copy ?

Shallow Copy

  • Whenever we use default implementation of clone method we get shallow copy of object means it creates new instance and copies all the fields of object to that new instance and returns it as object type.
  • clone() method of the object class support shallow copy of the object.
  • If the object contains primitive as well as non-primitive or reference type variable in shallow copy, the cloned object also refers to the same object to which the original object refers as only the object references gets copied and not the referred objects themselves.
  • If only primitive type fields or Immutable objects are there then there is no difference between shallow and deep copy in Java.
  • Refer lines 57-72 to see shallow copy constructor in above example.

Deep Copy

  • Whenever we need own copy not to use default implementation we call it as deep copy, whenever we need deep copy of the object we need to implement according to our need.
  • So for deep copy we need to ensure all the member class also implement the Cloneable interface and override the clone() method of the object class.
  • Refer lines 35-54 to see Deep copy constructor in above example.

When to use what
There is no hard and fast rule defined for selecting between shallow copy and deep copy but normally we should keep in mind that if an  object has only primitive fields, then obviously we should go for shallow copy, but if the object has references to other objects, then based on the requirement, shallow copy or deep copy should be done. If the references are not updated then there is no point to initiate a deep copy.

4.  What are the advantages of immutable class in java?

  • Immutable class is good for caching purpose because you don’t need to worry about the value changes. You can use static factory methods to provide methods like valueOf(), which can return an existing Immutable object from cache, instead of creating a new one.
  • Other benefit of immutable class is that it is inherently thread-safe, so you don’t need to worry about thread safety in case of multi-threaded environment.
  • The best use of the immutable objects is as the keys of a Map and values of Set.
  • Once created the state of the immutable object can not be changed so there is no possibility of them getting into an inconsistent state.

Please feel free to comment in case of any doubts.

Leave a Comment

Bitnami