Skip to content

Lesson 06 · Sealed Types

Objectives

After this lesson you will be able to:

  • Declare sealed classes and interfaces with a permits clause.
  • Apply the rule that each permitted subtype is final, sealed, or non-sealed.
  • State the accessibility / location / direct-extension constraints on permitted subtypes.
  • Combine sealed hierarchies with records for exhaustive switch (algebraic data types).

sealed and permits

A sealed class or interface restricts which types may extend or implement it, making the hierarchy closed and fully known to the compiler.

java
sealed interface Shape permits Circle, Square { }

record Circle(double r) implements Shape { }      // final (records are final)
final class Square implements Shape {
    final double side;
    Square(double side) { this.side = side; }
}

Every permitted subtype must itself choose one of:

  • final — no further subclassing (records are automatically final),
  • sealed — continues the closed hierarchy with its own permits,
  • non-sealed — re-opens that branch to any subclass.
java
sealed class Vehicle permits Car, Truck { }
final class Car extends Vehicle { }
non-sealed class Truck extends Vehicle { }        // anyone may extend Truck
class Pickup extends Truck { }                    // legal — Truck re-opened the branch

A sealed type may be abstract (a common base with abstract methods), and a sealed interface can permit both classes and other interfaces.

Rules for permitted subtypes

A permitted subtype must satisfy all of:

RuleWhy
be one of final / sealed / non-sealedkeeps the hierarchy's closedness explicit
directly extend/implement the sealed typepermits lists direct subtypes only
be accessible to the sealed typethe compiler must see it to check exhaustiveness
live in the same module (named) or same package (unnamed module)locality of the closed set

Exam trap

A permitted subtype that is none of final/sealed/non-sealed does not compile. The permits clause may be omitted when all subtypes are declared in the same source file (the compiler infers it). A type listed in permits that doesn't actually extend the sealed type is a compile error.

Exhaustive switch with sealed types

Because the compiler knows the complete set of subtypes, a switch over a sealed type can be exhaustive without a default — and it errors if you miss a case or add a new subtype later.

java
double area(Shape s) {
    return switch (s) {
        case Circle c -> Math.PI * c.r() * c.r();
        case Square sq -> sq.side() * sq.side();
        // no default needed — Circle and Square exhaust Shape
    };
}

SDET note

Sealed + records + exhaustive switch turn "did I handle every case?" into a compile-time check. Add a new permitted subtype and every non-exhaustive switch fails to compile — the compiler becomes a regression test for missing branches.

Algebraic data types (sealed + records + patterns)

The killer combination: a sealed interface with record implementations models a closed set of shapes of data, and a pattern switch deconstructs them — recursively, with no default.

java
sealed interface Expr permits Num, Add { }
record Num(int value) implements Expr { }
record Add(Expr left, Expr right) implements Expr { }

int eval(Expr e) {
    return switch (e) {
        case Num(int v)            -> v;
        case Add(Expr l, Expr r)   -> eval(l) + eval(r);
    };
}

Beyond the exam

At runtime you can inspect a sealed type reflectively: Shape.class.isSealed() and getPermittedSubclasses(). This is reflection territory (Module 11), not a 1Z0-830 objective — but it confirms the closed set the compiler enforces.

Key Takeaways

  • sealed … permits A, B closes a class or interface to a known set; permits may be omitted when subtypes share the file. A sealed type may be abstract.
  • Each permitted subtype must be final, sealed, or non-sealed, directly extend the sealed type, be accessible, and live in the same module/package.
  • non-sealed re-opens a branch to arbitrary subclasses.
  • A switch over a sealed type can be exhaustive without default; missing a subtype is a compile error.
  • Sealed interfaces + records + pattern switch model algebraic data types with compiler-checked exhaustiveness.

Lesson Quiz

Lesson Quiz · Sealed Types0 / 7
  1. A permitted subtype of a sealed type must be...

    • Apublic
    • Bfinal, sealed, or non-sealed
    • Cabstract
    • Da record
  2. When can the permits clause be omitted?

    • ANever
    • BWhen all permitted subtypes are in the same source file
    • CWhen the type is public
    • DWhen there is only one subtype
  3. Why can this switch omit default?

    sealed interface S permits A, B {}
    // switch over an S handling case A, case B
    • Adefault is always optional
    • BThe compiler knows A and B are the only subtypes (exhaustive)
    • CS is an interface
    • DIt can't — default is required
  4. What does non-sealed mean?

    • ASeals the type further
    • BRe-opens that branch to any subclass
    • CMakes the type final
    • DRemoves it from the hierarchy
  5. Which is NOT a requirement for a permitted subtype?

    • AIt directly extends/implements the sealed type
    • BIt is final, sealed, or non-sealed
    • CIt is declared public
    • DIt is in the same module (or same package in the unnamed module)
  6. Can a sealed class also be abstract?

    • ANo
    • BYes
    • COnly if it has no permits
    • DOnly sealed interfaces can
  7. Given non-sealed class Truck extends Vehicle {}, is class Pickup extends Truck {} legal?

    • AYes — Truck re-opened the branch
    • BNo — Pickup must be permitted
    • CNo — Truck is sealed
    • DOnly if Pickup is final

Next: Nested & Inner Classes. Run the matching code in labs/src/main/java/com/jse21/m03_oop/.