ReviseAlgo Logo

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.

Last Updated: June 13, 2026 10 min read

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 final to leverage compiler constant folding.
  • If you want a collection to be truly read-only, wrap it using List.of() or Collections.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.