final Keyword in Java
final Keyword in Java
final is Java's way of locking something down. Depending on where you place it, it can lock a variable's value, a method's implementation, or an entire class's ability to be extended. This chapter walks through all three uses.
final Variables and Constants
A variable marked final can be assigned exactly once. After that single assignment, any attempt to reassign it is a compile-time error, not a runtime one, so the mistake is caught immediately rather than surfacing later in production.
final int MAX_USERS = 100;
// MAX_USERS = 200; // COMPILE ERROR: cannot reassign a final variable
final int score; // 'blank final' declared without a value
score = 95; // legal — this is its one and only assignment
// score = 80; // COMPILE ERROR — already assigned once
By convention, constants combine static and final together, and are named in uppercase with underscores, signalling clearly that the value is fixed for the entire application, not just for one object.
class PhysicsConstants {
static final double SPEED_OF_LIGHT = 299792458; // metres per second
static final double GRAVITY = 9.8;
}
It is worth knowing that final only locks the reference itself, not necessarily the contents of what it points to. A final array or object reference still allows its contents to change.
final int[] scores = {10, 20, 30};
scores[0] = 99; // legal — modifying contents is fine
// scores = new int[5]; // COMPILE ERROR — reassigning the reference itself is not
final Methods and Preventing Override
A method marked final cannot be overridden by any subclass. This is useful when a method's behaviour is critical to correctness, and you want to guarantee that no subclass can silently change what it does.
class PaymentProcessor {
final void validateTransaction(double amount) {
if (amount <= 0) {
throw new IllegalArgumentException("Invalid amount");
}
System.out.println("Transaction validated");
}
}
class CreditCardProcessor extends PaymentProcessor {
// void validateTransaction(double amount) { } // COMPILE ERROR — cannot override a final method
}
This is commonly used in security-sensitive or framework-style code, where the author wants to allow extension in some places (regular, overridable methods) while locking down a specific core piece of logic that subclasses must never be able to bypass or alter.
final Classes and Preventing Inheritance
A class marked final cannot be extended by any other class at all. Attempting class Sub extends FinalClass will simply fail to compile.
final class ImmutablePoint {
private final int x;
private final int y;
ImmutablePoint(int x, int y) {
this.x = x;
this.y = y;
}
int getX() { return x; }
int getY() { return y; }
}
// class FastPoint extends ImmutablePoint { } // COMPILE ERROR — ImmutablePoint is final
Java's own String class is a well-known example of a final class. This is deliberate: if String could be subclassed, code throughout the standard library that relies on String's exact, predictable behaviour could be undermined by a malicious or careless subclass overriding its methods.
Use of final | Effect |
final variable | Can be assigned only once; reassignment is a compile-time error |
final method | Cannot be overridden by any subclass |
final class | Cannot be extended (subclassed) by any other class |
Quick Tip
Marking a class final is also a common technique when building immutable classes, objects whose state can never change after construction, such as ImmutablePoint above. Combining a final class, final fields, and no setters is the standard recipe for immutability in Java, and immutable objects are inherently thread-safe, since no thread can ever change their state after creation.










