Skip to main content
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.

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.

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.

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.
Tired of Poor Java Skills? Fix That With Deep Grasping!Learn More