Question 1 · Section 13

What is an immutable (unchangeable) object?

An immutable (unchangeable) object is an object whose state does not change after creation. All fields are set once in the constructor, and after that the object provides no way...

Language versions: English Russian Ukrainian

Basic Level

An immutable (unchangeable) object is an object whose state does not change after creation. All fields are set once in the constructor, and after that the object provides no way to modify its data.

This means the object is created once and forever remains in the same state — like a photograph that cannot be edited.

Simple Example

public final class Point {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() { return x; }
    public int getY() { return y; }
    // No setters — state cannot be changed
}

Key Characteristics

  • No setters (setX, setY, etc.)
  • All fields are private final
  • Class is final (cannot be subclassed)

When NOT to use immutable objects

  1. High-allocation hot-path — millions of modifications/sec, GC pressure
  2. Massive data structures — copying is more expensive than mutation
  3. Prototypes and scripts — development speed is more important than reliability

Immutable vs final fields vs no setters

  • No setters ≠ immutable: you can still modify through returned references to mutable fields
  • Final fields ≠ immutable: if a field references a mutable object, it can be changed
  • Immutable: no observable state changes after construction

Intermediate Level

Five Rules for Creating an Immutable Class

  1. The class must be final — subclasses cannot add mutable state
  2. All fields are private final — access only through getters
  3. No mutator methods — no setX(), add(), remove()
  4. Protect mutable fields — if a field references a modifiable object (e.g., List or Date), you must make defensive copies
  5. Safe publication — do not expose this during construction

Working with collections

public final class UserProfile {
    private final String username;
    private final List<String> roles;

    public UserProfile(String username, List<String> roles) {
        this.username = username;
        this.roles = List.copyOf(roles); // defensive copy
        // List.copyOf returns a new independent list.
        // If null is passed — NPE will be thrown, so add a null-check.
    }

    public List<String> getRoles() {
        return roles; // List.copyOf already returned an immutable list
    }
}

Modern approach — Records (Java 14+)

public record UserProfile(String username, List<String> roles) {
    public UserProfile {
        roles = List.copyOf(roles);
    }
}

A record automatically makes the class final, fields private final, and generates the constructor, equals(), hashCode(), and toString().


Advanced Level

Java Memory Model (JMM) Guarantees

Using final fields provides safe publication. According to the JMM specification, after the constructor of an immutable object completes, any thread that obtains a reference to this object is guaranteed to see the correct values of its final fields. This eliminates the need for volatile or synchronization.

At the end of the constructor, a “freeze” of all final fields occurs — a memory barrier is created that prevents instruction reordering.

Performance and Garbage Collection

It is commonly believed that immutability harms performance. But in HotSpot JVM (the main OpenJDK implementation): allocation in Young Generation is extremely fast (Bump-the-pointer — just moving a pointer). Other JVMs (Zing, GraalVM) may differ:

  • Short-lived objects are cleaned up for free during Minor GC
  • No Write Barriers (no modification of Old Generation)

Constructor Escape Danger

public ImmutableClass() {
    ExternalService.register(this); // ERROR! Object published before initialization completes
}

Another thread may see final fields in their default state (null or 0).

Deep Copy for Nested Mutable Objects

If the list contains not String but mutable User objects, List.copyOf is insufficient — each element must be cloned.

Summary for Advanced

  • Immutability is a “security contract”
  • final at the class and field level is a JMM requirement
  • Always make copies of mutable components
  • Use Records to reduce boilerplate

Interview Cheat Sheet

Must know:

  • Immutable object — state doesn’t change after creation
  • Three key characteristics: final class, private final fields, no setters
  • Five rules: final class, private final fields, no mutators, protect mutable fields, safe publication
  • List.copyOf() / Collections.unmodifiableList() for collection protection
  • Records (Java 14+) automatically generate an immutable class
  • JMM guarantees safe publication for final fields after construction
  • Immutability ≠ thread-safe for references to mutable objects
  • Constructor Escape — critical error of publishing this before the constructor completes

Frequent follow-up questions:

  • Are final fields enough? — No, you also need mutable field protection and a final class
  • What is deep copy? — Recursive copying of all nested mutable objects
  • When NOT to use immutability? — High-allocation hot-path, massive structures, prototypes
  • Records vs regular class? — Records: minimal boilerplate, but no inheritance and no extra fields

Red flags (DO NOT say):

  • “Immutable = just no setters” — mutable fields can still be changed through getters
  • “Final fields are enough” — without defensive copy, mutable objects are vulnerable
  • “Immutability is always slower” — in a multi-threaded environment without locks, it’s faster
  • “You can change an immutable object via reflection” — this is blocked in Java 17+

Related topics:

  • [[2. What advantages do immutable objects provide]]
  • [[3. How to create an immutable class in Java]]
  • [[7. What is the final keyword and how does it help create immutable classes]]
  • [[8. Is it enough to make all fields final for immutability]]
  • [[20. What is a Record and how does it help create immutable classes]]