Detailed explanation
In Java, final is a keyword that restricts changes to variables, methods, and classes. A final variable cannot be reassigned after initialization, a final method cannot be overridden, and a final class cannot be subclassed. These restrictions communicate design intent and are checked by the compiler. However, final does not automatically enforce object immutability: it protects a variable's assignment or prevents inheritance-based changes, depending on where it is used.
For variables, final means assignment is allowed only once. For example, final int MAX = 100; is valid, but a later MAX = 200; causes a compilation error. A final variable does not always need an initializer at its declaration. A blank final instance field can be assigned in a constructor, provided it is definitely assigned exactly once on every normally completing construction path. With a reference variable, final prevents assigning a different object, not modifying the existing object. For example, after final List<String> names = new ArrayList<>();, names.add("Asha") is valid, while names = new ArrayList<>(); is not. A final parameter similarly cannot be reassigned inside its method.
For methods, final prevents a subclass from overriding inherited behaviour. A superclass might use it to preserve an algorithm or validation rule while still allowing inheritance elsewhere. A final method can still be overloaded with a different parameter list. For classes, final prevents all subclassing: final class Utility {} cannot be extended. String is a familiar final class, but its immutability also depends on its internal implementation, not merely the final modifier. A class cannot be both abstract and final because abstract expects subclass implementation while final forbids subclassing.
In interviews, the important distinction is between restricting reassignment, restricting overriding, and restricting inheritance. Interviewers may also check whether you confuse final with static: final controls reassignment or extension, whereas static makes a member belong to the class rather than individual instances. Constants commonly use static final together. Understanding these differences helps you explain both what the compiler prevents and what remains changeable at runtime.
Key points to remember
- A final variable can be assigned only once; a blank final variable may be initialized later under definite-assignment rules.
- A final reference cannot point to another object, but the referenced object may remain mutable.
- A final method cannot be overridden, but it can be overloaded.
- A final class cannot be extended; String is a standard example.
- static final commonly declares constants, but not every final variable is a compile-time constant.
Common mistakes candidates make
- Claiming that final makes every referenced object immutable.
- Saying that final methods cannot be overloaded.
- Assuming every final variable must be initialized at its declaration.
Likely follow-up questions
What is the difference between final, finally, and finalize()?
final is a modifier that restricts reassignment, overriding, or inheritance; finally is a block used with try for cleanup. finalize() is a legacy Object method associated with garbage collection, deprecated for removal and unsuitable for reliable resource cleanup.
Is every static final variable a compile-time constant?
No: a constant variable must have a primitive or String type and be initialized with a constant expression. For example, static final int LIMIT = 100; qualifies, but static final Integer LIMIT = 100; does not.
What does effectively final mean?
A local variable is effectively final if it is not declared final but is never reassigned after initialization. Lambdas and local or anonymous classes can capture local variables only when they are final or effectively final.
Interview tip: State the three uses first, then demonstrate reassignment failure and clarify that a final reference does not make its object immutable.
