Understanding Final Classes in Java
Learn when and why to use final classes in Java. Understand the design principle of prohibiting inheritance for better code safety.
Moshiour Rahman
Advertisement
What is a Final Class?
A final class is simply a class that cannot be extended. Any attempt to subclass it results in a compile-time error.
final class Owl {
public void hoot() {
System.out.println("Hoot!");
}
}
// Compilation Error: Cannot extend final class 'Owl'
class TechyOwl extends Owl {
}
Common Misconceptions
A final class does NOT mean:
- All references to objects of this class are final
- All fields in the class are automatically final
- The class is immutable
A final class can still have mutable fields:
final class Counter {
private int count = 0; // Mutable field
public void increment() {
count++; // State can change
}
}
When Should You Use Final Classes?
Preventing Illogical Inheritance
Consider this problematic code:
public class Car {
public void move() {
System.out.println("Driving on road");
}
}
// This compiles but makes no sense!
public class Airplane extends Car {
@Override
public void move() {
System.out.println("Flying in air");
}
}
An Airplane should not extend Car - they’re fundamentally different concepts. Using final prevents such design mistakes:
public final class Car {
public void move() {
System.out.println("Driving on road");
}
}
Joshua Bloch’s Guidance
In Effective Java, Joshua Bloch advises:
Design and document for inheritance or else prohibit it.
The interaction between subclasses and parent classes can be unpredictable if the parent wasn’t designed for inheritance.
Classes Should Be One of Two Types
- Classes designed for extension - Well-documented with clear extension points
- Final classes - Explicitly prohibit inheritance
Real-World Examples
Java Standard Library
Many core Java classes are final:
// All of these are final classes
String text = "Hello";
Integer number = 42;
Long bigNumber = 100L;
Why? Because these classes are immutable and their behavior must be guaranteed.
Security-Sensitive Classes
public final class SecurityValidator {
public boolean validateToken(String token) {
// Critical security logic
return isValid(token);
}
}
Making security classes final prevents attackers from creating malicious subclasses that bypass security checks.
Final vs Sealed Classes (Java 17+)
Java 17 introduced sealed classes for more granular control:
// Only specific classes can extend
public sealed class Vehicle permits Car, Motorcycle, Truck {
// ...
}
public final class Car extends Vehicle { }
public final class Motorcycle extends Vehicle { }
public final class Truck extends Vehicle { }
This provides a middle ground between open inheritance and complete prohibition.
Best Practices
When to Use Final
- Utility classes - Classes with only static methods
- Immutable classes - Value objects that shouldn’t change
- Security-critical classes - Prevent tampering via subclassing
- Classes not designed for extension - The default choice
When NOT to Use Final
- Framework base classes - Like Spring’s
Controllerclasses - Template pattern implementations - Where subclassing is the design
- Test doubles - Mocking frameworks need to extend classes
The Composition Principle
Using final also supports the principle of favoring composition over inheritance:
// Instead of extending
public final class EnhancedList<E> {
private final List<E> delegate;
public EnhancedList(List<E> delegate) {
this.delegate = delegate;
}
public void add(E element) {
delegate.add(element);
}
// Add new behavior without inheritance
public E getLastElement() {
return delegate.get(delegate.size() - 1);
}
}
Conclusion
The final keyword for classes is a powerful design tool:
- Five characters that prevent future maintenance headaches
- Signals that the class wasn’t designed with inheritance in mind
- Can always be removed later if needed (but harder to add)
- Supports composition over inheritance
Key Takeaways:
- Make classes
finalby default unless you explicitly design for extension - Document extension points if you do allow inheritance
- Use
sealedclasses in Java 17+ for controlled hierarchies - Consider composition as an alternative to inheritance
Advertisement
Moshiour Rahman
Software Architect & AI Engineer
Enterprise software architect with deep expertise in financial systems, distributed architecture, and AI-powered applications. Building large-scale systems at Fortune 500 companies. Specializing in LLM orchestration, multi-agent systems, and cloud-native solutions. I share battle-tested patterns from real enterprise projects.
Related Articles
The Visitor Design Pattern: Add Operations Without Modifying Classes
Master the Visitor Pattern in Java. Learn how to add new operations to object structures using double dispatch.
JavaThe Template Method Pattern: The Recipe for Success
Master the Template Method Pattern in Java. Learn how to define the skeleton of an algorithm in a superclass but let subclasses override specific steps.
JavaThe Observer Design Pattern: Don't Call Us, We'll Call You
Master the Observer Pattern in Java. Learn how to implement event-driven architectures and decouple data sources from listeners.
Comments
Comments are powered by GitHub Discussions.
Configure Giscus at giscus.app to enable comments.