Sealed Classes

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • Sealed Classes (introduced in Java 15, finalized in Java 17) allow a class or interface to strictly define which other classes are allowed to extend or implement it.
  • They provide fine-grained control over inheritance, bridging the gap between final (no inheritance allowed) and normal classes (infinite inheritance allowed).
  • They are heavily used with Pattern Matching for exhaustive switch statements.

Concept

Before Java 17, inheritance was a free-for-all. If you created a public class Shape, anyone anywhere in your codebase (or a 3rd party using your library) could create a subclass of it. To prevent this, you had to make the class final, but that meant you couldn’t subclass it either!

A Sealed Class solves this. You declare a class as sealed and use the permits keyword to explicitly list the exact classes that are allowed to extend it.
If someone tries to create class Triangle extends Shape, the compiler will throw an error because Triangle is not on the permitted list.

Examples

// 1. Define the Sealed Class and its permitted subclasses
public sealed class Shape permits Circle, Square, Rectangle {
    public abstract double calculateArea();
}

// 2. Permitted subclasses MUST declare their own inheritance status:
// They must be 'final', 'sealed', or 'non-sealed'.

// A. 'final' - No one can extend this further. The hierarchy ends here.
public final class Circle extends Shape {
    public double radius;
    public double calculateArea() { return Math.PI * radius * radius; }
}

// B. 'sealed' - Continues the controlled hierarchy.
public sealed class Rectangle extends Shape permits Square {
    public double w, h;
    public double calculateArea() { return w * h; }
}
public final class Square extends Rectangle {
    // Inherits from Rectangle
}

// C. 'non-sealed' - Opens the hierarchy back up to everyone!
// Any random class in the project can now extend UserShape.
public non-sealed class UserShape extends Shape {
    public double calculateArea() { return 0; }
}

Interview Questions

Q: What are the constraints for permitted subclasses?
A: For a class to extend a sealed class, it must meet three strict requirements:

  1. It must be explicitly listed in the permits clause of the sealed class.
  2. It must exist in the exact same package (or the same module, if using Java Modules) as the sealed class.
  3. It must explicitly declare itself as final, sealed, or non-sealed to define the future of the inheritance tree.

Q: How do Sealed Classes improve switch statements?
A: They allow for Exhaustive Pattern Matching. Because the compiler knows exactly how many subclasses of Shape exist in the entire universe, if you write a switch(shape) statement that checks case Circle, case Square, and case Rectangle, the compiler knows you have covered 100% of the possibilities. It will not force you to write a default case!