Final Keyword in Java with Examples: Variables, Methods, and Classes

Final Keyword in Java with Examples: Variables, Methods, and Classes


The final keyword in Java is a small word with big impact. It lets you lock down values, methods, and even entire classes so they cannot be changed in ways you don’t want. In this tutorial for students and beginners, we’ll explore the final keyword in Java with examples. You will learn what final does for variables, methods, and classes, why it’s useful, how to use it, and common mistakes to avoid. If you’re just starting your Java journey, also check our main Java tutorials for more basics.

What is final in Java?

final keyword in Java with examples: visualizing final variables, single assignment, constructor initialization
Final variables at a glance: assign once, allow constructor assignment—great for constants.

In Java, final prevents modification:

  • final variable in Java: can be assigned only once.
  • final method in Java: cannot be overridden (or hidden if static).
  • final class in Java: cannot be subclassed.

These three uses help you express intent (single assignment), protect code from accidental changes (prevent overriding), and design reliable APIs (no subclassing where it doesn’t make sense). Let’s go through each with simple examples and best practices.

Final keyword in Java — at a glance (with examples)

  • Variable: single assignment only.
    final int LIMIT = 100;
  • Method: cannot be overridden.
    public final void validate() { ... }
  • Class: cannot be subclassed.
    public final class Token { ... }

final variable in Java

final keyword in Java with examples: class hierarchy showing final methods not overridden and final classes not extended
Final methods can’t be overridden; final classes can’t be extended in Java.

Syntax

Code
final dataType variableName = value; // assign exactly once

final keyword in Java with simple examples

Code
class="cd-keyword cd-access">public class FinalVariableBasics {
    class="cd-keyword cd-access">public static void main(String[] args) {
        final int maxStudents = 30;
        System.out.println("Max = " + maxStudents);

        // maxStudents = 31; // Compile-time error: cannot assign a value to final variable
    }
}
Output
Max = 30

Once you assign a final variable, you cannot reassign it.

final on object references (important!)

When a reference variable is final, the reference cannot change, but the object it points to can still change (if it’s mutable):

Code
class="cd-package">import java.util.ArrayList;
class="cd-package">import java.util.List;

class="cd-keyword cd-access">public class FinalReferenceDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        final List<String> ids = new ArrayList<>();
        ids.add("A");        // OK: modifying the object
        ids.add("B");        // OK
        System.out.println(ids);

        // ids = new ArrayList<>(); // Compile-time error: cannot reassign final reference
    }
}
Output
[A, B]

Blank final fields (assign later, once)

A blank final is declared without an initializer and must be assigned exactly once before use—commonly in a constructor. This is how you create immutable fields for each object instance.

Code
class="cd-keyword cd-access">public class Student {
    class="cd-keyword cd-access">private final String rollNo; // blank final
    class="cd-keyword cd-access">private final String name;   // blank final

    class="cd-keyword cd-access">public Student(String rollNo, String name) {
        this.rollNo = rollNo; // assigned once here
        this.name = name;     // assigned once here
    }

    class="cd-annotation">@Override
    class="cd-keyword cd-access">public String toString() {
        return rollNo + ": " + name;
    }

    class="cd-keyword cd-access">public static void main(String[] args) {
        Student s = new Student("R001", "Asha");
        System.out.println(s);
    }
}
Output
R001: Asha

Constants with static final

Use static final for constants (especially primitives and Strings). By convention, constant names are uppercase with underscores:

Code
class="cd-keyword cd-access">public class MathUtil {
    class="cd-keyword cd-access">public static final double PI = 3.141592653589793;

    class="cd-keyword cd-access">public static void main(String[] args) {
        System.out.println(2 * PI);
    }
}
Output
6.283185307179586
  • If a static final primitive or String is initialized with a compile-time constant, compilers may inline it. Prefer private static final constants inside classes to avoid accidental coupling.
  • All interface fields are implicitly public static final.

Effectively final and lambdas (beginner tip)

Local variables used inside lambdas or inner classes must be final or effectively final (assigned once). You don’t need the keyword if you never reassign the variable.

Code
class="cd-keyword cd-access">public class LambdaFinalDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        int base = 10; // effectively final (assigned once)

        Runnable r = () -> System.out.println("Base = " + base);
        r.run();

        // base++; // Uncommenting this makes ___CDPHSTR1___ not effectively final -> compile-time error
    }
}
Output
Base = 10

From Java 10 onward, you can combine final with var for single-assignment with type inference:

Code
class="cd-keyword cd-access">public class FinalVarDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        final var msg = "Hello"; // type inferred as String
        System.out.println(msg);
        // msg = ___CDPHSTR1___; // error: cannot assign a value to final variable
    }
}
Output
Hello

final method in Java

A final method cannot be overridden in subclasses. This is useful when you want to lock down behavior that must not change, e.g., validation logic, security checks, or lifecycle hooks.

Why a final method cannot be overridden (example)

Code
class Base {
    class="cd-keyword cd-access">public final void greet() {
        System.out.println("Hello from Base");
    }
}

class Child extends Base {
    // @Override
    // public void greet() { } // Compile-time error: cannot override final method

    class="cd-keyword cd-access">public void wave() {
        System.out.println("Child waves");
    }
}

class="cd-keyword cd-access">public class FinalMethodDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        Child c = new Child();
        c.greet(); // calls Base.greet()
        c.wave();
    }
}
Output
Hello from Base
Child waves

Static final methods and method hiding

static methods can also be final. A subclass cannot hide a final static method:

Code
class A {
    class="cd-keyword cd-access">public static final void ping() {
        System.out.println("A.ping");
    }
}

class B extends A {
    // public static void ping() {} // Compile-time error: cannot hide final method
}

class="cd-keyword cd-access">public class StaticFinalMethodDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        B.ping(); // resolves to A.ping()
    }
}
Output
A.ping

final class in Java

A final class cannot be subclassed. Use it when you want to prevent inheritance—for example, to keep invariants safe or to avoid misuse of an API. java.lang.String is a famous final class.

How to use a final class in Java (real-world idea)

  • Utility or helper classes whose behavior shouldn’t be extended.
  • Security-sensitive types to prevent tampering via subclassing.
  • Immutable value types where subclassing could break invariants.
Code
final class ApiClient {
    class="cd-keyword cd-access">public void request() {
        System.out.println("Requesting...");
    }
}

// class MockClient extends ApiClient {} // Compile-time error: cannot subclass final class

class="cd-keyword cd-access">public class FinalClassDemo {
    class="cd-keyword cd-access">public static void main(String[] args) {
        ApiClient client = new ApiClient();
        client.request();
    }
}
Output
Requesting...

Immutability and concurrency: final fields matter

final fields help you build immutable objects and improve thread-safety. The Java Memory Model gives special guarantees to final fields: after the constructor finishes, properly published objects make their final fields safely visible to other threads. This is one reason immutable classes use private final fields and no setters.

Note: final alone does not make an object immutable. You must design for immutability (final fields, no setters, avoid exposing mutable internals).

Code
class="cd-keyword cd-access">public final class Point {
    class="cd-keyword cd-access">private final int x;
    class="cd-keyword cd-access">private final int y;

    class="cd-keyword cd-access">public Point(int x, int y) {
        // assign all final fields in the constructor
        this.x = x;
        this.y = y;
    }

    class="cd-keyword cd-access">public int x() { return x; }
    class="cd-keyword cd-access">public int y() { return y; }

    class="cd-annotation">@Override
    class="cd-keyword cd-access">public String toString() {
        return "(" + x + "," + y + ")";
    }

    class="cd-keyword cd-access">public static void main(String[] args) {
        Point p = new Point(2, 3);
        System.out.println(p);
        // p.x = 5; // error: x has private access, and it's final
    }
}
Output
(2,3)

Records are implicitly final

Java records are concise data carriers. Every record class is implicitly final, and each component becomes a private final field with an accessor. This makes records great for immutable data.

Code
class="cd-keyword cd-access">public record Person(String name, int age) {
    class="cd-keyword cd-access">public static void main(String[] args) {
        Person p = new Person("Ria", 20);
        System.out.println(p.name() + " " + p.age());
        // p.age = 21; // error: fields are final
    }
}
Output
Ria 20

Common mistakes and quick tips

  • Thinking final makes objects immutable: It doesn’t by itself. A final reference can still point to a mutable object. Design for immutability using private final fields and no mutators.
  • Forgetting to initialize blank finals: Every code path in a constructor must assign all blank final fields exactly once.
  • Expecting performance boosts: final is a semantic constraint, not a performance promise. Don’t use it for micro-optimizations.
  • Reassigning effectively final locals used in lambdas: If you change a local variable after using it in a lambda, compilation fails.
  • Changing public static final constants later: Compilers may inline constant values. Keep constants private where possible to avoid compatibility issues.
  • Overusing inheritance: If a class wasn’t designed for extension, make it final to avoid fragile hierarchies.
  • final with var: You can write final var x = … for single-assignment with type inference (Java 10+).

FAQ: People Also Ask

What does the final keyword do in Java?

It prevents change at three levels: a final variable can be assigned only once, a final method cannot be overridden (or hidden if static), and a final class cannot be subclassed. Use it to express invariants and protect APIs.

How do I create a final variable in Java?

Declare with the final keyword and assign exactly once:

Code
final int limit = 100;     // assigned at declaration
// or
final String id;           // blank final
id = "U101";               // assigned later, exactly once (before use)

Can a final method be overridden in Java?

No. A final method cannot be overridden in a subclass. Attempting to do so is a compile-time error. For static methods, final prevents method hiding as well.

When should I use a final class in Java?

Use a final class when subclassing would break invariants or complicate maintenance, such as:

  • Immutable value objects (e.g., Money, Point).
  • Security-sensitive or correctness-critical types.
  • Utilities or API endpoints where behavior must not vary.

What is the difference between final, finally, and finalize in Java?

Term Where it applies Prevents / Guarantees Quick example Notes
final (keyword) Variables, methods, classes Reassignment, overriding, subclassing final int N=5;
final void f(){}
final class C{}
Core to immutability and API safety
finally (block) try-catch-finally Cleanup code always runs try{...} finally {close();} Use try-with-resources when possible
finalize (method) Object cleanup hook Legacy GC callback (deprecated) protected void finalize(){} Deprecated; avoid using
  • final: a keyword for variables, methods, and classes (prevents change).
  • finally: a block in try-catch-finally that always executes (resource cleanup).
  • finalize(): a method once used for cleanup by the GC; it’s deprecated and should be avoided. Use try-with-resources or explicit close methods instead.

When to use final in your code

Start → Ask: “What do I need to protect?”
Need a value assigned once? → Use final variable
private final String id;
Need behavior that must not change in subclasses? → Use final method
public final void checkAccess() { ... }
Want to block inheritance entirely? → Use final class
public final class Credentials { ... }
Bonus: For immutable types, combine final fields, no setters, and defensive copies.

  • Model constants: private static final int MAX_RETRIES = 3;
  • Immutable domain objects: private final fields set in the constructor.
  • Method-level guarantees: final method to lock down critical behavior.
  • API design: final class to prevent unsafe or unintended extension.
  • Functional style: final/effectively final locals used in lambdas.

Practice and next steps

Try converting a mutable class you wrote into an immutable one by using private final fields and no setters. Add one final method that validates state and cannot be overridden. If you’re exploring more Java basics and OOP topics, head back to our Java section on CodDesire.

Sources / Further reading

Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted