Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A sealed class or interface restricts the inheritance hierarchy by explicitly defining which other classes or interfaces are permitted to extend or implement it. Finalized in Java 17, this mechanism provides exhaustive, compiler-enforced control over subtyping, allowing developers to define a strictly closed set of subclasses. To declare a sealed class, apply the sealed modifier to the class declaration, followed by the permits clause. The permits clause specifies the exact types allowed to directly extend the sealed class. The permitted subclasses must be available at compile time, otherwise the compiler will throw an error.
public sealed class Shape permits Circle, Rectangle, Triangle {
    // Class implementation
}

final class Circle extends Shape {}
final class Rectangle extends Shape {}
final class Triangle extends Shape {}

Subclass Modifier Rules

The compiler enforces strict inheritance rules on any class or interface extending or implementing a sealed type. Every permitted subclass must define its inheritance boundaries. Standard classes must explicitly use exactly one of the following three modifiers:
  1. final: Terminates the hierarchy. The subclass cannot be extended further.
  2. sealed: Continues the restricted hierarchy. The subclass restricts its own extensions (either via an explicit permits clause or implicitly if its own subclasses are declared in the same source file).
  3. non-sealed: Re-opens the hierarchy. The subclass behaves like a standard Java class and can be extended by any unknown class.
Specialized types handle these boundaries implicitly. record types are implicitly final, and enum types are implicitly final (or sealed if they contain class bodies). Because records and enums implicitly extend java.lang.Record and java.lang.Enum respectively, Java’s single class inheritance rule dictates they can never extend a sealed class; they can only implement a sealed interface. When implementing a sealed interface, records and enums do not require explicit inheritance modifiers.
public sealed interface Expression permits ConstantExpr, PlusExpr, EvalExpr, ValueExpr {}

// 1. Terminates the hierarchy
final class ConstantExpr implements Expression {}

// 2. Continues the restricted hierarchy
sealed class PlusExpr implements Expression permits FastPlusExpr {}
final class FastPlusExpr extends PlusExpr {}

// 3. Re-opens the hierarchy
non-sealed class EvalExpr implements Expression {}
class LazyEvalExpr extends EvalExpr {} // Allowed because EvalExpr is non-sealed

// Implicitly final (no explicit modifier required)
record ValueExpr(int value) implements Expression {}

Compilation Constraints

The Java compiler enforces several structural constraints on sealed classes and their permitted subclasses:
  • Direct Extension: Every type listed in the permits clause must directly extend or implement the sealed type.
  • Module and Package Locality:
    • If the sealed class belongs to a named module, all permitted subclasses must belong to the same module.
    • If the sealed class belongs to an unnamed module, all permitted subclasses must reside in the same package.
  • Interface Compatibility: The sealed and non-sealed modifiers, as well as the permits clause, apply identically to interfaces. A sealed interface restricts which interfaces can extend it and which classes or records can implement it.

Implicit Permitting (Same-File Declarations)

If a sealed class and all of its subclasses are declared within the exact same source file, the permits clause can be omitted. The Java compiler will automatically infer the permitted subclasses based on the file contents.
public sealed class Result {
    // The compiler implicitly infers: permits Success, Failure
}

final class Success extends Result {}
final class Failure extends Result {}

Reflection API Support

The java.lang.Class API includes methods to inspect sealed classes at runtime:
  • isSealed(): Returns true if the class or interface is sealed.
  • getPermittedSubclasses(): Returns an array of Class<?> objects representing all permitted subclasses, including both those explicitly declared in a permits clause and those implicitly inferred by the compiler via same-file declarations. If the class or interface is not sealed, this method returns null (not an empty array), which must be handled to avoid NullPointerExceptions.
Master Java with Deep Grasping Methodology!Learn More