Basics

15. The final Keyword

final means different things depending on context: for variables it means assign-once; for methods it prevents overriding; for classes it prevents inheritance; for parameters it prevents reassignment inside the method.

Java 21 (core language)

Explanation

final variable: must be assigned exactly once; blank finals (fields declared final without an initialiser) must be set in every constructor. This applies to local variables, instance fields, and class (static) fields.

final method: cannot be overridden by a subclass. All private methods are implicitly final (they can't be overridden anyway, just hidden).

final class: cannot be subclassed at all. String, Integer, and all other wrapper classes are final. This enables optimisations and guarantees immutability invariants.

final parameter: the parameter variable cannot be reassigned inside the method body. It does not affect the caller (Java is pass-by-value). It's a compile-time guard against accidental shadowing and common in anonymous classes (where captured variables must be effectively final).

Example

public class FinalKeyword {
    // final field โ€” must be set in constructor
    private final String name;
    private static final int MAX_SIZE = 100; // compile-time constant

    FinalKeyword(String name) {
        this.name = name; // blank final assigned in constructor
    }

    // final method โ€” cannot be overridden
    public final String getName() { return name; }

    // final class โ€” cannot be subclassed
    static final class ImmutablePoint {
        final int x, y;
        ImmutablePoint(int x, int y) { this.x = x; this.y = y; }
    }

    // final parameter โ€” cannot reassign inside method
    static int add(final int a, final int b) {
        // a = 0; // compile error!
        return a + b;
    }

    public static void main(String[] args) {
        // final local variable
        final String greeting = "Hello";
        // greeting = "Hi"; // compile error!

        // effectively final: captured by lambda without explicit final
        String prefix = "Mr. "; // effectively final โ€” not reassigned
        Runnable r = () -> System.out.println(prefix + "Smith");
        r.run();

        System.out.println("MAX_SIZE: " + MAX_SIZE);
        System.out.println("add(3,4): " + add(3, 4));

        ImmutablePoint p = new ImmutablePoint(1, 2);
        System.out.println("Point: (" + p.x + ", " + p.y + ")");
    }
}

Sources