What is an immutable class and how do you create one?
An immutable class is a class whose instances cannot be modified after construction. Once created, an immutable object's state is fixed for its lifetime. java.lang.String, Integer, and the other wrapper types are the canonical examples.
Immutable objects offer significant advantages: they are inherently thread-safe (no synchronization needed since state cannot change), safe to share and cache, easy to reason about, and make excellent keys in HashMap or elements in HashSet because their hashCode never changes.
To create an immutable class, follow these five rules:
1. Declare the class final (or use private constructors with static factory methods) to prevent subclassing that could override methods and introduce mutability. 2. Make all fields private and final so they are set once in the constructor and cannot be reassigned. 3. Do not provide any setter methods or other mutating methods. 4. Perform defensive copies of mutable objects passed into the constructor. If a constructor accepts a Date or a List, copy it immediately — otherwise a caller could mutate the external reference after construction, changing the object's state. 5. Perform defensive copies of mutable objects returned from getters. If a field is a mutable collection, return a copy or an unmodifiable view — otherwise callers can mutate the internal state through the reference.
Record classes introduced in Java 16 provide a concise immutable class syntax: the compiler auto-generates a canonical constructor, private final fields, accessors (not getters in JavaBeans style), equals(), hashCode(), and toString(). However, records don't automatically deep-copy mutable fields — you still need a compact constructor to perform defensive copies if fields contain mutable types.
A common mistake is thinking that declaring a field final makes the object it references immutable. final only prevents reassigning the reference; the referenced object itself can still be mutated if it is a mutable type.
Lists the core rules (final class, private final fields, no setters, defensive copies) and explains why immutability implies thread safety.
Distinguishes field-level final (reference immutable) from object-level immutability, explains both incoming and outgoing defensive copies, mentions Java Records as the modern idiom, and gives HashMap key safety as a practical benefit.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment