🧬 Inheritance & Polymorphism · Intermediate

final classes & methods in Java

Preventing extension and overriding.

🧩 The mysteryCould you write class EvilString extends String and make every password check return true? Java's designers made very sure you can't.

final class: end of the line

A **final class cannot be extended** — any class Sub extends FinalClass is a compile error. String, Integer and Math are all final classes.

public final class String { ... }

final method: no overrides

A **final method is inherited but cannot be overridden**. Every subclass uses exactly that implementation. Overloads — same name, different parameters — are still allowed, because they're different methods.

class A {
    final void f() { }
}
class B extends A {
    void f(int x) { }  // OK: overload
}
🔮 Predict it

Breaking into the vault

What happens?

final class Vault { }
class Thief extends Vault { }
void main() { System.out.println("in!"); }
  1. in!
  2. Compile error
  3. Throws IllegalAccessError
Show the answer

Compile error. Vault is final, so the compiler refuses to let Thief extend it. Nothing runs at all.

Locking one step

Why make just one method final in a class open for extension? To protect a critical algorithm: a final play() fixes the order of steps, while subclasses customize the individual, non-final steps. That's the *template method* pattern.

abstract class Game {
    final void play() {
        start(); turn(); end();
    }
    abstract void turn();
}
⚠️ The trap

Don't assume

Not every JDK class is final: **ArrayList isn't** — you can extend it (though composition is usually better). And final on a private or static method adds nothing for overriding: those can't be overridden anyway.

💼 In the real world

In real projects

String being final is a security feature: nobody can sneak in a mutable "String" subclass that changes after a permission check. Library authors follow the rule "design for inheritance or prohibit it" — and final is how you prohibit it.

Key takeaways

  1. final class: no subclasses
  2. final method: no overrides (overloads are still fine)
  3. private and static methods can't be overridden anyway
  4. Common in immutable and security-sensitive types
🤯 Did you know?

Kotlin made this the default: classes and methods there are final unless you mark them open.

Practice questions

What does this print?

final class Base { }
class Sub extends Base { }
void main() { System.out.println("ok"); }
  1. ok
  2. Compile error
  3. Throws IllegalAccessError
Check your answer

Compile error. Base is final, so the compiler refuses to let Sub extend it.

What does this print?

class A { final void f() { } }
class B extends A {
    void f() { }
}
void main() { System.out.println("ok"); }
  1. ok
  2. Compile error
  3. Prints ok; B.f() silently replaces A.f()
Check your answer

Compile error. f() is final in A, so B may not override it.

Next: a class you can never create on purpose — abstract classes.