thecodex.expert · The Codex Family of Knowledge
Java

Sealed Classes

A normal Java class can be extended by absolutely anyone, anywhere — sealed is how you say exactly which classes are allowed to, and no others.

Java 21 LTS Finalized in Java 17 Last verified:
Canonical Definition

sealed on a class or interface, combined with a permits clause listing the allowed direct subtypes, restricts inheritance to exactly that named set — unlike an ordinary Java class, which any code anywhere can extend. Each permitted subclass must itself be declared final, sealed (with its own further-restricted permits list), or non-sealed (explicitly reopening it to unrestricted extension). Because the compiler now has complete, closed knowledge of every possible subtype, a switch over a sealed type's subtypes can be verified exhaustive at compile time, with no default branch required.

Declaring a sealed hierarchy

Any class outside this permits list attempting to extend Shape is a compile error — the hierarchy is closed by design, not just by convention.

JavaShape.java
public sealed interface Shape permits Circle, Square, Triangle { }

public final class Circle implements Shape {
    public double radius;
}

public final class Square implements Shape {
    public double side;
}

public final class Triangle implements Shape {
    public double base, height;
}

// public class Hexagon implements Shape { }   // COMPILE ERROR: not in permits list

Each subclass must declare its own inheritance status

final closes it completely (Circle above); sealed continues the restriction one level further; non-sealed deliberately reopens that one branch to unrestricted extension — every permitted subclass must pick exactly one of these three.

Javanon_sealed_example.java
public sealed interface Shape permits Circle, Square, CustomShape { }

public final class Circle implements Shape { }       // closed completely
public non-sealed interface CustomShape extends Shape { }  // reopened — anyone can implement this branch

Exhaustive pattern matching: no default needed

Because the compiler knows Circle, Square, and Triangle are the ONLY possible subtypes, a switch covering all three is verified exhaustive at compile time — adding a fourth permitted subtype later would make this switch a compile error until updated, catching an easily-missed case immediately rather than silently at runtime.

Javaexhaustive_switch.java
double area(Shape shape) {
    return switch (shape) {
        case Circle c -> Math.PI * c.radius * c.radius;
        case Square s -> s.side * s.side;
        case Triangle t -> 0.5 * t.base * t.height;
        // no default needed — compiler verifies these 3 cases are ALL of them
    };
}

Sources

1
Oracle. Java Language Specification, "Sealed Classes and Interfaces," docs.oracle.com/en/java/javase/25/language/sealed-classes-and-interfaces.html, and JEP 409.