Why is the `final` keyword important for security and immutability, and why is `java.lang.String` final?
answer
- final stops malicious/behavior-changing subclasses
- String final → no mutable subclass → no TOCTOU swap
- true immutability needs final fields AND final class
- final method protects one security-critical step
- Effective Java: design for inheritance or prohibit it
basics
~20 sMarking a class final stops anyone from subclassing it to inject malicious or behavior-changing code. String is final so an attacker can't subclass it to make a "string" whose value secretly changes after a security check, which keeps it safely immutable.
solid answer
~50 s`final` is a security and immutability tool because it removes a subclass's ability to override behavior. If `String` were not final, an attacker could write a mutable subclass and pass it where a `String` is expected; code that validated the value (say a file path or SQL fragment) could then have that value *change* after the check — a classic time-of-check/time-of-use attack. By being final, `String` guarantees the instance you validated is the instance you use. The same logic protects immutability: true immutability needs all fields final *and* the class final, otherwise a subclass could add mutable state or override accessors to return changing values. Final classes also let the JVM and security manager reason about a type's behavior with confidence, and they enable JIT devirtualization. So `final` enforces a security-relevant invariant — "this type behaves exactly as written" — at compile time.
code
java · 15 lines// If String were extensible, this attack would be possible:
class EvilString /* extends String — illegal, String is final */ {
private int calls = 0;
public String toString() {
return (calls++ == 0) ? "/safe/file" : "/etc/passwd"; // value flips
}
}
void open(String path) {
if (isAllowed(path)) { // checks "/safe/file"
readFile(path); // would read "/etc/passwd" if value could change
}
}
// Because String is FINAL + IMMUTABLE, its value can never change between
// the check and the use — the TOCTOU swap is impossible.go deeper
Knows String is final and that final stops subclassing; can say it's 'safer' without the full mechanism.
Connects final to immutability (final fields + final class) and can explain that subclasses could otherwise add mutable state.
Articulates the TOCTOU attack a mutable String subclass would enable, the full immutability recipe, and final methods as targeted defense.
Weighs final vs sealed classes vs private constructors across an API, discusses reflection/module-system limits, JIT devirtualization, testability trade-offs, and cites Effective Java's 'design for inheritance or prohibit it'.
## The core mechanism When a class is *not* final, anyone can write `class Evil extends Safe {}` and **override** its methods, substituting their own logic. Polymorphism means an `Evil` instance can be passed anywhere a `Safe` is expected, and callers can't tell the difference at the call site. `final` removes that possibility: a final class has **no subclasses**, so its methods always run exactly the code the author wrote. ## Why this matters for security: TOCTOU A **time-of-check/time-of-use (TOCTOU)** bug is when a program *checks* a value, then *uses* it later, and the value changes in between. Consider: ```java void open(String path) { if (isAllowed(path)) { // check readFile(path); // use } } ``` If `String` could be subclassed into a *mutable* form, an attacker could pass a string that returns `"/safe/file"` during `isAllowed(...)` and `"/etc/passwd"` during `readFile(...)`. The validation would pass for one value while a different value is actually used. Because `String` is **final and immutable**, its characters can never change, so the value you validated is provably the value you use. This is precisely why the JDK makes `String` (and other security-sensitive types like `Integer`) final. ## Why `final` is required for true immutability An **immutable** object is one whose observable state cannot change after construction. The recipe is: (1) make all fields `private final`, (2) don't expose setters, (3) defensively copy mutable inputs/outputs, and crucially (4) **make the class final**. Why (4)? If the class is non-final, a subclass could: - add new *mutable* fields, making instances effectively mutable; - override a getter to return a value that changes over time; - override `equals`/`hashCode` to violate the contract a `HashMap` relies on. So a class that *looks* immutable but isn't final offers no real guarantee — callers receiving it as the base type can't trust it. Marking the class final closes that hole. (An alternative to a public final class is a non-final class with only private constructors, but final is the simplest, clearest sealing.) ## Final methods as a partial defense When you *need* the class to be extensible but a particular method must not be tampered with — e.g. a `validate()` or `checkPermission()` step — declare just that **method** final. Subclasses can extend the class but cannot replace that security-critical method. This is the template-method pattern used defensively: the fixed skeleton (final) calls customizable hooks (non-final). ## Secondary benefits - **JIT devirtualization / inlining:** because a final method/class has exactly one possible implementation, the JIT can resolve calls statically and inline them, sometimes improving performance. (Modern JITs also do this speculatively for non-final code, so this is a minor, not primary, reason.) - **Clear API contracts:** final says "this is a leaf, compose don't extend," reducing the surface other code can break. ## The trade-off Final reduces flexibility: you can't mock a final class/method with older mocking tools, and you can't extend it for legitimate reasons. The guidance (e.g. *Effective Java* Item 18–19) is: **design and document for inheritance or else prohibit it** — and prohibiting it via `final` is the safe default for value types and security-sensitive classes. ## How to derive the answer Start from "what can a subclass do?" → override behavior and add state. Then ask "what breaks if it does?" → a validated value could change (TOCTOU), an 'immutable' object could mutate, contracts could be violated. `final` forbids subclassing/overriding, so those attacks become impossible at compile time — that is the security and immutability value.
- Does making a class final fully protect it from tampering via reflection?No. `final` only prevents subclassing/overriding. Reflection (with sufficient permissions / `setAccessible`) can still read and sometimes mutate private fields. Final guards the inheritance vector specifically; protecting against reflection requires the module system, SecurityManager (legacy), or simply not exposing mutable state. For `String`, immutability plus final means even reflective mutation would be both hard and a violation of strong invariants the JVM relies on.
- If a class has all final fields but is not itself final, is it immutable?Not guaranteed. A subclass can add mutable fields or override accessors to return changing values, so callers holding the base type cannot rely on immutability. For a trustworthy immutability guarantee the class should also be final (or use private constructors).
saying these in an interview costs you the question
- Saying String is final only for performance — security/immutability is the primary reason
- Claiming final alone makes a class immutable — it also needs final fields, no setters, defensive copies
- Thinking final prevents reflection-based attacks — reflection can still read private state; final guards inheritance, not all access
- Believing immutability has no security relevance