Object-Oriented Programming
final Keyword
Analyze final variables (primitives vs references), final class inheritance blocks, and compile-time constant folding optimizations.
Interview: Focuses on blank final variable initializations, final reference mutations, constant folding rules, and final classes.
The final keyword enforces immutability and restricts extension. It can be applied to variables, methods, and classes to establish code invariants.
Core Idea
final variables cannot be reassigned once initialized. final classes cannot be extended.
Why It Matters
final reference variables prevent address reassignment, but their internal state can still be mutated unless the object itself is immutable.
Interview Lens
Tests blank final initializations in constructors, reference mutations, and compiler constant folding rules.
final Variables: Value vs. Reference Immutability
When declaring a variable as final, understand the type behavior differences:
- Primitive variables: The value is immutable and cannot be changed (e.g.,
final int x = 5;cannot be reassigned). - Reference variables: The reference variable cannot be reassigned to point to another object. However, the internal state of the referenced object can still be mutated (e.g. elements can be added to a final
ArrayList). - Blank final variables: A final variable declared without an initial value. It must be initialized in every constructor (for instance fields) or in the static block (for static fields) before compilation completes.
Constant folding optimization
If a final variable is initialized with a compile-time constant expression (e.g., public static final int LIMIT = 100;), the compiler performs Constant Folding:
The compiler replaces all references to LIMIT directly with the literal value 100 in the compiled bytecode, eliminating runtime lookup overhead.
Common Pitfalls
- Assuming Reference Immutability: Assuming a final collection (like
final List<String> list) is read-only, and getting caught when elements are mutated. - Omitting initialization: Declaring a blank final instance variable and failing to initialize it in one of the class constructors.
- Over-restricting inheritance: Declaring classes final when inheritance extension is needed for testing or customization.
Best Practices
- Mark variables as final by default, especially in multi-threaded contexts, to minimize mutable state.
- When declaring constants, compile them as
public static finalto leverage compiler constant folding. - If you want a collection to be truly read-only, wrap it using
List.of()orCollections.unmodifiableList(), rather than just marking the reference as final.
Interview-Relevant Information
Q1: Does marking a reference variable final make the referenced object immutable?
Answer: No. It only prevents the reference variable from being reassigned to a different object address. The underlying object's fields can still be modified, and elements can still be added or removed if the object is mutable.
Q2: What is a blank final variable, and when must it be initialized?
Answer: A blank final variable is a final variable declared without an initial value. Blank final instance variables must be initialized in every constructor of the class. Blank final static variables must be initialized in the class's static block.
Quick Checklist
Can you distinguish reference from value immutability, declare and initialize blank final fields, explain constant folding rules, and apply final class blocks? If yes, you understand final.
Use Cases
Declaring immutable application ID keys inside API configuration services.
Wrapping sensitive reference lists inside unmodifiable collections to protect state integrity.
Common Mistakes
Failing to initialize blank final variables inside overloaded constructor branches.
Expecting final list variables to automatically block runtime list mutations.