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
Singleton Design Pattern in Java: Part 1
Deep dive into the Singleton design pattern in Java. Learn different implementation approaches including eager initialization and lazy loading.
JavaLombok: Reduce Java Boilerplate Code
Complete guide to Project Lombok for Java. Learn how to eliminate boilerplate code with annotations like @Data, @Builder, and @RequiredArgsConstructor.
JavaSingleton Design Pattern in Java: Part 2
Advanced singleton implementations including Double-Checked Locking with volatile and the Bill Pugh pattern using static inner classes.
Comments
Comments are powered by GitHub Discussions.
Configure Giscus at giscus.app to enable comments.