Sealing Classes
JEP 409 — finalized in Java 17. Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them, giving the compiler a closed, exhaustive type hierarchy.
Why Sealed Classes?
Before sealed classes, a class was either final (no subclasses allowed) or open to any subclass anywhere. There was no middle ground. Sealed classes introduce a third option: a fixed, known set of permitted subtypes.
This is valuable for:
- Domain modeling — a
Shapecan only beCircle,Rectangle, orTriangle. - Pattern matching — the compiler can verify switch exhaustiveness over a sealed hierarchy without a
defaultbranch. - API safety — library authors control the hierarchy without making it final.
sealed and permits
Use the sealed modifier on a class or interface, followed by a permits clause listing all allowed direct subtypes:
javapublic sealed class Shape permits Circle, Rectangle, Triangle {}Each permitted subclass must be in the same package (or same module if using modules) and must be compiled together with the sealed class.
Subclass Constraints
Every class named in the permits clause must choose one of three modifiers:
| Modifier | Meaning |
|---|---|
final |
Cannot be extended further |
sealed |
Can be extended, but only by its own permits list |
non-sealed |
Reopens the hierarchy — anyone can extend |
javapublic sealed class Shape permits Circle, Rectangle, Triangle {}
public final class Circle extends Shape {
private final double radius;
public Circle(double radius) { this.radius = radius; }
public double radius() { return radius; }
}
public sealed class Rectangle extends Shape permits Square {
private final double width, height;
public Rectangle(double width, double height) {
this.width = width; this.height = height;
}
public double width() { return width; }
public double height() { return height; }
}
public final class Square extends Rectangle {
public Square(double side) { super(side, side); }
}
public non-sealed class Triangle extends Shape {
// anyone may now extend Triangle
}Forgetting to add final, sealed, or non-sealed to a permitted subclass is a compile-time error.
Sealed Interfaces
Interfaces can also be sealed. Permitted subtypes may be classes, abstract classes, or other interfaces:
javapublic sealed interface Expr permits Num, Add, Mul {}
public record Num(int value) implements Expr {}
public record Add(Expr left, Expr right) implements Expr {}
public record Mul(Expr left, Expr right) implements Expr {}Records are implicitly final, so they satisfy the subclass constraint automatically.
Interaction with Pattern Matching in switch
The primary payoff of sealed hierarchies is exhaustive switch expressions without a default branch:
javapublic sealed interface Shape permits Circle, Rectangle, Triangle {}
public record Circle(double radius) implements Shape {}
public record Rectangle(double w, double h) implements Shape {}
public record Triangle(double base, double h) implements Shape {}
static double area(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.w() * r.h();
case Triangle t -> 0.5 * t.base() * t.h();
// no default needed — compiler sees the sealed hierarchy is covered
};
}If you add a new permitted subtype to Shape, the compiler immediately flags every non-exhaustive switch as an error — making the codebase safe to evolve.
permits Clause Can Be Omitted
If all permitted subclasses are in the same compilation unit (same source file), the permits clause is inferred automatically:
java// SingleFile.java
public sealed class Vehicle {}
final class Car extends Vehicle {}
final class Truck extends Vehicle {}
// permits inferred: Car, TruckRules Summary
| Rule | Detail |
|---|---|
sealed keyword |
Placed before class or interface |
permits clause |
Lists all allowed direct subtypes |
| Subclass location | Same package (or module) as sealed class |
| Subclass obligation | Must be final, sealed, or non-sealed |
| Records | Implicitly final — satisfy constraint automatically |
non-sealed |
Breaks the seal — anyone may extend that branch |
| Exhaustive switch | Compiler verifies without default when hierarchy is sealed |
Common Exam Traps
- A class listed in
permitsthat is not a direct subclass fails to compile. - A permitted subclass that is missing
final/sealed/non-sealedfails to compile. non-sealedis valid Java syntax (a keyword with a hyphen); writingnonsealedwithout the hyphen is a compile-time error.- Sealed classes can be
abstract.
References
- JEP 409: Sealed Classes (Java 17)
- Oracle Docs — Sealed Classes and Interfaces
- OCP Study Guide, Chapter 6 — Class Design