Immutability requires controlling reachable mutable state, not only declaring fields final. Constructors and accessors must protect ownership.
Before you start
You should know Java classes, methods, collections and exceptions. Trace object identity separately from the contents of an object. For concurrent examples, state which thread owns or shares the data; a single successful execution is not proof that every interleaving is safe.
The practical goal is to reason through this situation: Copy a mutable input collection and avoid exposing a mutable internal collection. Read the walkthrough first, then try the interview exercise before opening its answer. The important part is explaining the decision and its consequences, rather than remembering a definition alone.
Step-by-step walkthrough
Step 1: Identify reachable mutation
A final collection reference can still contain mutable data.
Step 2: Protect construction
Copy caller-owned mutable collections before retaining them.
Step 3: Protect access
Return immutable values and define nested element ownership too.
Worked scenario
Copy a mutable input collection and avoid exposing a mutable internal collection.
Caller A passes a mutable list into configuration C. If C stores it directly, A can later alter C by editing that list. List.copyOf separates the container and prevents container mutation through the result, but mutable elements still require a separate policy.
Common mistake
Final prevents field reassignment but not mutation of its referenced object.
Verify the behavior
Mutate constructor input and returned values; verify configuration does not change unexpectedly.
Interview exercise
Create an immutable configuration.
Answer and reasoning
Validate once, copy mutable inputs and expose immutable views or values whose elements obey the ownership contract.
Continue learning
Compare the scenario with the Java interview questions and test your understanding with the Java MCQs. For terminology and implementation details, consult the reference material.