Java Sealed Classes
java sealed classes permits final non-sealed sealed interface pattern matching records Java 17
Learning Objectives
After completing this lesson, you will be able to:
- Understand what Sealed Classes are
- Learn why Sealed Classes were introduced
- Differentiate between
sealed,non-sealed, andfinal - Restrict class inheritance
- Create Sealed Interfaces
- Use
permitsclause - Combine Sealed Classes with Records
- Use Pattern Matching with Sealed Classes
- Understand JVM Internals
- Apply Sealed Classes in Enterprise Applications
- Follow Best Practices
- Prepare for Java Interview Questions
Introduction
One of the biggest challenges in Object-Oriented Programming is uncontrolled inheritance.
Consider the following class:
public class Vehicle {}
Any developer can create:
class Car extends Vehicle {}class Bike extends Vehicle {}class Truck extends Vehicle {}class Airplane extends Vehicle {}class UFO extends Vehicle {}
Nothing prevents developers from extending Vehicle.
Sometimes this is desirable.
However, in enterprise applications, some class hierarchies should remain controlled.
Examples:
- Payment Types
- HTTP Responses
- Shapes
- AST (Abstract Syntax Tree)
- Banking Transactions
- Compiler Nodes
- State Machines
Java 17 introduced Sealed Classes to solve this problem.
Why Sealed Classes?
Suppose we are building a payment system.
Without restrictions
class Payment {}class Cash extends Payment {}class Card extends Payment {}class Bitcoin extends Payment {}class RandomPayment extends Payment {}
Anyone can create new subclasses.
Sometimes this breaks business rules.
Instead
public sealed class Paymentpermits Cash,Card,UPI{}
Only approved subclasses are allowed.
What is a Sealed Class?
A Sealed Class restricts which classes or interfaces can extend or implement it.
Syntax
public sealed class Shapepermits Circle,Rectangle{}
Only:
- Circle
- Rectangle
can extend Shape.
Java Version
| Feature | Version |
|---|---|
| Preview | Java 15 |
| Second Preview | Java 16 |
| Standard | Java 17 |
Basic Example
public sealed class Vehiclepermits Car,Bike{}
Allowed
public final class Carextends Vehicle{}
public final class Bikeextends Vehicle{}
Not Allowed
class Truckextends Vehicle{}
Compilation Error.
permits Clause
The permits keyword explicitly lists permitted subclasses.
public sealed class Animalpermits Dog,Cat,Lion{}
Rules
Every permitted subclass must declare one of the following:
- final
- sealed
- non-sealed
final Subclass
Cannot be extended further.
public final class Dogextends Animal{}
Hierarchy
Animal↓Dog(End)
sealed Subclass
Can continue restricting inheritance.
public sealed class Mammalextends Animalpermits Dog,Cat{}
non-sealed Subclass
Removes restrictions.
public non-sealed class Birdextends Animal{}
Now
class Eagleextends Bird{}
is valid.
Sealed Class Hierarchy
Animal (sealed)│┌──────────────┼──────────────┐│ │ │Dog(final) Mammal(sealed) Bird(non-sealed)│┌──────┴──────┐│ │Cat Tiger
Sealed Interfaces
Interfaces can also be sealed.
public sealed interface Paymentpermits CardPayment,CashPayment{}
Implementation
public final class CardPaymentimplements Payment{}
Combining Records with Sealed Classes
One of the most common enterprise use cases.
public sealed interface Shapepermits Circle,Rectangle{}
public record Circle(double radius)implements Shape{}
public record Rectangle(double width,double height)implements Shape{}
Records and Sealed Interfaces work together beautifully for immutable domain models.
Pattern Matching with Sealed Classes
(Java 21)
static double area(Shape shape){return switch(shape){case Circle c ->Math.PI *c.radius() *c.radius();case Rectangle r ->r.width() *r.height();};}
Since all subclasses are known, the compiler can verify that the switch is exhaustive.
Reflection with Sealed Classes
Check whether a class is sealed.
System.out.println(Shape.class.isSealed());
Output
true
Retrieve permitted subclasses.
Class<?>[] classes =Shape.class.getPermittedSubclasses();for(Class<?> clazz : classes){System.out.println(clazz.getSimpleName());}
Sealed Class Internals
Conceptually
Shape↓Compiler↓Restricts inheritance↓JVM verifies subclasses
The JVM enforces the permitted subclass list.
Sealed Classes vs Final Classes
| Final | Sealed |
|---|---|
| No subclass allowed | Selected subclasses allowed |
| Completely closed | Partially closed |
| One-level restriction | Controlled hierarchy |
Sealed Classes vs Abstract Classes
| Abstract | Sealed |
|---|---|
| Anyone may extend | Only permitted classes may extend |
| No inheritance restriction | Controlled inheritance |
| Can be open-ended | Explicit hierarchy |
Real-World Example: Payment System
public sealed interface PaymentpermitsCardPayment,UPIPayment,CashPayment{}
Only approved payment implementations are allowed.
Real-World Example: API Response
public sealed interface ApiResponsepermitsSuccess,Failure{}
public record Success(String message)implements ApiResponse{}
public record Failure(String error)implements ApiResponse{}
Real-World Example: Banking
public sealed class TransactionpermitsDeposit,Withdrawal,Transfer{}
This prevents unauthorized transaction types.
Spring Boot Use Cases
Sealed classes are useful for:
- API response models
- Domain events
- Business rule hierarchies
- CQRS commands
- Event sourcing
- Workflow states
They are less common for JPA entities because entity inheritance is often designed differently.
Best Practices
Use Sealed Classes for Closed Hierarchies
Examples:
- Shapes
- Payment Types
- Commands
- Events
- States
Combine with Records
Records provide immutable data.
Sealed interfaces provide controlled inheritance.
Together they produce concise and type-safe models.
Prefer Pattern Matching
Java 21 switch expressions become safer with sealed hierarchies.
Keep Hierarchies Small
Avoid deeply nested sealed hierarchies.
Document the Hierarchy
Clearly describe why subclasses are restricted.
Common Mistakes
Forgetting final, sealed, or non-sealed
Wrong
class Dogextends Animal{}
Compilation Error.
Every permitted subclass must declare one of these modifiers.
Forgetting permits
The compiler must know the permitted subclasses unless they are declared in the same compilation unit where inference rules apply.
Using Sealed Classes Everywhere
Use them only when the hierarchy should be intentionally closed.
Expecting Runtime Extension
Sealed classes enforce inheritance restrictions at compile time and runtime.
Confusing final with sealed
final↓No subclasses.sealed↓Specific subclasses.
Hands-on Exercise
Create a Java program that:
- Creates a sealed Shape class.
- Creates Circle and Rectangle as permitted subclasses.
- Creates a sealed interface named Payment.
- Implements CardPayment and CashPayment.
- Creates a non-sealed subclass.
- Creates a final subclass.
- Combines Records with a sealed interface.
- Uses pattern matching with a switch expression.
- Uses Reflection to inspect permitted subclasses.
- Builds a small banking transaction hierarchy using sealed classes.
Summary
Sealed Classes, introduced as a standard feature in Java 17, allow developers to explicitly control inheritance by specifying which classes or interfaces may extend or implement a type. Together with Records and Pattern Matching, they enable expressive, type-safe, and maintainable domain models. Sealed Classes are particularly valuable for modeling closed business hierarchies such as payments, commands, states, and events in modern enterprise applications.
Key Takeaways
- Sealed Classes restrict inheritance.
- The
permitsclause lists allowed subclasses. - Every permitted subclass must be
final,sealed, ornon-sealed. - Sealed Interfaces work the same way as sealed classes.
- Records integrate naturally with sealed hierarchies.
- Pattern Matching becomes exhaustive with sealed types.
- Reflection can inspect sealed hierarchies.
- Use Sealed Classes for closed domain models.
- Do not replace every abstract class with a sealed class.
- Sealed Classes are a major feature of modern Java (Java 17+).
Professional Interview Questions
1What are Sealed Classes in Java?
Professional Answer
Sealed Classes are a Java feature introduced as a standard feature in Java 17 that allow developers to explicitly control which classes or interfaces can extend or implement a type. They provide compile-time and runtime enforcement of a closed inheritance hierarchy, making domain models safer and easier to maintain.
Follow-up Questions
- Which Java version standardized Sealed Classes?
- What keyword lists permitted subclasses?
Interview Tip: Sealed Class = Controlled Inheritance.
2What is the difference between sealed, final, and non-sealed?
Professional Answer
A sealed class restricts inheritance to a predefined set of permitted subclasses. A final class completely prevents further inheritance. A non-sealed class removes the restriction imposed by a sealed superclass, allowing unrestricted subclassing again. Every direct subclass of a sealed class must explicitly declare one of these three modifiers.
Follow-up Questions
- Can a sealed class have a non-sealed subclass?
- Why must every permitted subclass declare one of these modifiers?
Interview Tip: final → No Children, sealed → Selected Children, non-sealed → Open Again.
3Why are Sealed Classes useful with Records and Pattern Matching?
Professional Answer
Sealed Classes define a closed hierarchy, Records provide concise immutable data carriers, and Pattern Matching enables exhaustive type-safe processing. Together, they allow the compiler to verify that all possible cases are handled, resulting in cleaner, safer, and more maintainable code for business domains such as payments, workflow states, and command processing.
Follow-up Questions
- Why can the compiler verify an exhaustive switch over a sealed hierarchy?
- What enterprise scenarios benefit most from this combination?
Interview Tip: Records → Immutable Data, Sealed Classes → Controlled Hierarchy, Pattern Matching → Type-Safe Processing.