final Variables in Java — Constants and Immutable References
Fast recall
Quick revision
Core answer
Understanding the distinction between a final reference and an immutable object — a classic gotcha
Thinking final makes an object immutable — it only prevents reassignment of the reference, not modification of the object's contents
Clarify the difference between a final reference and a truly immutable object, and mention final instance variables must be initialized in the constructor or at declaration
Interview-ready guide
Interview answer
The thing that trips people up here isn't what final does — it's how far it reaches. `final` makes a variable assign-once: bind it, and any later reassignment is a compile error. For a primitive that's the obvious constant behaviour — final int max = 100 and max is 100 forever.
The twist is with object references. When you write final List of String names = new ArrayList, what's locked is the reference — the arrow pointing at that list. You can never repoint it at a different list, but names.add is completely legal, because that mutates the list's contents, not which list names points to. So `final` stops reassignment; it does not stop mutation. A final reference is not an immutable object. If you want contents that genuinely can't change, that's a separate decision — List.of, or a class with no setters and final fields, the way String is built.
There's also a rule the compiler enforces: a `final` instance variable has to be assigned exactly once, either at its declaration or in every constructor path — you can't leave it unset. In practice I use final liberally on fields and parameters, because it documents that a value shouldn't change and lets the compiler catch an accidental reassignment before it ever becomes a bug.
final Variables in Java — Constants and Immutable References
Direct Answer
final on a variable means it can be assigned only once. For primitives the value can't change; for object references the reference can't be repointed — but the object's internal state can still be mutated. It's the reference that's final, not the object.
Code Example
This puts every flavour of final in one class so you can see the rules side by side — a constant set at declaration, a field set once in the constructor, a locked local, and a locked reference whose object still mutates.
public class FinalDemo {
private final String company = "TechCorp"; // set at declaration
private final int foundedYear;
public FinalDemo(int year) { this.foundedYear = year; } // set once in constructor
void demo() {
final int maxRetries = 3;
// maxRetries = 5; // COMPILE ERROR
final var names = new java.util.ArrayList<String>();
names.add("Alice"); // OK — mutating the list is allowed
System.out.println(company + " " + foundedYear + " " + names);
}
}
Notice foundedYear has no value at its declaration — that's legal only because the constructor assigns it on every path. Miss one path and the compiler rejects the class outright.
Common Mistakes & Pitfalls
- Confusing final reference with immutability:
final List<String> items = new ArrayList<>();still allowsitems.add(...).finalonly blocks reassigningitems. - Not initializing final instance variables: they must be set at declaration or in every constructor, or it's a compile error.
- Thinking final freezes the object globally: another method holding the same reference can still mutate the object.
Check your understanding
Answer these without looking back at the article.
- What is the difference between final, finally, and finalize in Java?
- Can a final variable be null?
- How is a final variable different from a constant in other languages?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.