Immutable Classes

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • An Immutable Class is a class whose instances cannot be modified after they are created.
  • Example: String and Integer are immutable.
  • To create one: Make the class final, fields private final, provide no setters, and deeply clone mutable objects in getters.

Concept

Immutable objects are inherently thread-safe because multiple threads cannot change their state. They are also excellent candidates for keys in a HashMap because their hash code will never change.

Steps to create an Immutable Class:

  1. Declare the class as final so it can’t be extended (child classes could override methods to mutate state).
  2. Make all fields private and final.
  3. Initialize all fields via a constructor.
  4. Do not provide any setter methods.
  5. Crucial: If the class contains mutable objects (like Date or List), return a deep copy or clone of them in the getter, rather than the original reference.

Examples

import java.util.ArrayList;
import java.util.List;

// 1. Class is final
public final class ImmutableStudent {
    // 2. Fields are private and final
    private final String name;
    private final List<String> courses;

    // 3. Initialized in constructor
    public ImmutableStudent(String name, List<String> courses) {
        this.name = name;
        // MUST deep copy mutable objects passed into constructor
        this.courses = new ArrayList<>(courses); 
    }

    // 4. No Setters! Only Getters.
    public String getName() {
        return name;
    }

    public List<String> getCourses() {
        // 5. MUST return a copy of the mutable object, not the original reference
        return new ArrayList<>(courses); 
    }
}

Interview Questions

Q: Why must we return a copy of a List in the getter of an immutable class?
A: If you simply return this.courses;, you are returning the memory reference to the list. The caller could then do student.getCourses().add("Hacking");. Even though your class has no setters and the field is final, the contents of the list would be mutated, breaking immutability. Returning a new copy prevents this.

Q: Are Java Records immutable?
A: Yes. Introduced in Java 14, record is a special class type designed to be an immutable data carrier. All fields in a record are implicitly private final, and it automatically generates getters, a constructor, equals, hashCode, and toString. However, if a record holds a mutable object (like an array or List), you still need to be careful with deep copying.