What does final mean in Java when it is applied to a class, a method, a variable and a parameter?
final means different things depending on what it is attached to, but the common thread is that it removes the possibility of change.
On a class, final means the class cannot be subclassed. This is what makes a class's design guarantees real: if Point is final, nobody can extend it and override its methods to break the contract, and the compiler can inline its calls.
On a method, final means the method cannot be overridden by a subclass. It is used for methods that hold a critical invariant, and it lets the JIT compiler devirtualise the call.
On a variable — a local, a parameter or a field — final means the variable cannot be reassigned after its initial assignment. For a local or parameter, the assignment happens at declaration. For a blank final field, it must be assigned exactly once, and the compiler proves it happens on every path through every constructor, including the delegation path.
On a parameter, final is a promise not to reassign the parameter inside the method. It is a readability and bug-prevention device rather than a language-level guarantee, since a method could always write to the same object through a different reference.
public class Main {
public static void main(String[] args) {
// A final local: assigned once, never reassigned.
final int limit = 10;
System.out.println("limit : " + limit);
// A final reference: the reference cannot move, but the object can change.
final StringBuilder sb = new StringBuilder("start");
sb.append("-changed");
System.out.println("final ref : " + sb);
Config c = new Config();
System.out.println("name : " + c.getName());
c.retry();
System.out.println("attempts : " + c.getAttempts());
}
}
final class Config { // cannot be subclassed
private final String name = "prod"; // assigned once
private int attempts; // not final, so it can change
public String getName() {
return name;
}
public int getAttempts() {
return attempts;
}
public void retry() {
attempts++;
}
}
class Base {
final void cannotOverride() { // cannot be overridden
System.out.println("base method");
}
}Note that Config mixes both: its name is final and its attempts counter is not, so the class has one piece of state that never changes and one that does. The final class modifier means nobody can subclass it to break those guarantees.