Creating Immutable Class in Java

This article shows how to create immutable classes in Java using suitable examples for a better explanation.

Immutable class in Java

Immutable classes are those classes whose object's state cannot be changed once created or any modification results in a new immutable object.

To better understand let's use a simple example of String and StringBuffer classes, any modification of a String object, in other words using substring, concat, and so on. results in a new immutable object when an operation is performed on the StringBuffer class but does not create a new immutable object. Instead it reflects the changes on the existing object only. Even JDK itself contains a number of immutable classes, like String, Float and other wrapper classes. We can also create an immutable class by creating a final class that has final data members.

Guidelines for making an immutable class in Java

The following are simple guidelines that can be followed to make a class immutable in Java:

  • Do not provide a setter method for the class because setter methods are used to change the state of the class's members.
  • Make all the fields final and private so that fields become non-accessible from outside the class and also their values will not be altered because of being final.
  • The class should not be sub-classed, so make them final that will prevent it from being overridden.
  • There is a need to focus on mutable reference variables with a reference variable, even final cannot prevent their values to be changed. So to prevent the reference variable's values, it's better to provide a copy of the object instead of providing an actual object.
  • Make the default constructor of the class private and provide instances with a factory method.

Example of making a class immutable by creating a final class

In the example given below, we create a final class named Student. There is only one final data member, a constructor and a getter method.

public final class Student

{

    final int RollNumber;

    public Student(int RollNumber)

    {

        this.RollNumber=RollNumber;

    }

    public int getRollNumber()

    {

       return RollNumber;

    }

}

The class in the preceding example is an immutable class because:

  • The instance variable of the class is final so after creating it we cannot change its value.
  • We cannot create a sub-class because the class is declared as final.
  • There is no setter method so there is no chance of changing the value of the instance variable.

Another example

Student.java

import java.util.Date;

 

// making class final which prevents it's methods overriden in subclasses

public final class Student

{

    private int RollNumber;

    private String Name;

    private Date CurrentDate;

 

    // private constructor ensures of no unwanted creation of objects

    private Student(int RollNumber, String Name, Date CurrentDate)

    {

        this.RollNumber=RollNumber;

        this.Name=Name;

        this.CurrentDate=CurrentDate;

    }

    // this holds the logic of object creation, only point to get an object

    static Student getInstance(int f1,String f2,Date f3)

    {

        return new Student(f1,f2,f3);

    } // integer class is immutable, this can be served directly

    public int getRollNumber()

    {

        return RollNumber;

    }

    // integer class is immutable, this can be served directly

    public String getName()

    {

       return Name;

    }

    //date class is mutable so we do not providing direct object, instead we providing a copy of it

    public Date getCurrentDate()

    {

       return new Date(CurrentDate.getTime());

    }

 

StudentImmutable.java

import java.util.Date;

 

public class StudentImmutable

{

    public static void main(String args[]) // getting an instance of immutable class

    {

        Student std=Student.getInstance(101,"Rakesh", new Date());

        System.out.println("RollNumber:"+ std.getRollNumber() +" Name:"+ std.getName() +" Date:"+std.getCurrentDate());

 

        // if you try to modify the object's state then

 

        // std.getRollNumber()=5; not permitted

        // std.getName()="Rahul" not permitted

 

        std.getCurrentDate().setDate(3);

        // printing the value again to test

        System.out.println("RollNumber:"+ std.getRollNumber() +" Name:"+ std.getName() +" Date:"+std.getCurrentDate());

    }

 

Output

Output

Up Next
    Ebook Download
    View all
    Learn
    View all