Java Sealed Classes
Restrict which classes can extend a class or implement an interface (Java 17+)
java (17+)
2025-11-03
sealed
inheritance
java17
pattern-matching
Description
Sealed classes and interfaces restrict which other classes or interfaces may extend or implement them. This provides more control over inheritance hierarchies and enables exhaustive pattern matching.
Key Features
- Sealed classes: Control which classes can extend them
- Sealed interfaces: Control which classes can implement them
- Permits clause: Explicitly lists allowed subclasses/implementations
- Non-sealed: Allows a subclass to be extended by any class
- Final: Prevents further inheritance
Benefits
- Controlled inheritance: Prevent unauthorized subclassing
- Exhaustive pattern matching: Compiler can verify all cases are handled
- Better design: Enforce design constraints at language level
- Documentation: Make inheritance hierarchy explicit
Use Cases
- Modeling algebraic data types
- State machines with known states
- API design with controlled extension points
- Pattern matching with exhaustive checking
Code
// Sealed classpublic sealed class Shape permits Circle, Rectangle, Triangle { public abstract double area();}// Final subclass (cannot be extended)public final class Circle extends Shape { private final double radius; public Circle(double radius) { this.radius = radius; } @Override public double area() { return Math.PI * radius * radius; }}// Final subclasspublic final class Rectangle extends Shape { private final double width, height; public Rectangle(double width, double height) { this.width = width; this.height = height; } @Override public double area() { return width * height; }}// Non-sealed subclass (can be extended)public non-sealed class Triangle extends Shape { protected double base, height; public Triangle(double base, double height) { this.base = base; this.height = height; } @Override public double area() { return 0.5 * base * height; }}// Can extend non-sealed classpublic class EquilateralTriangle extends Triangle { private double side; public EquilateralTriangle(double side) { super(side, side * Math.sqrt(3) / 2); this.side = side; }}// Sealed interfacepublic sealed interface Expression permits Constant, Variable, Addition, Multiplication { double evaluate();}public final class Constant implements Expression { private final double value; public Constant(double value) { this.value = value; } @Override public double evaluate() { return value; }}public final class Variable implements Expression { private final String name; private final double value; public Variable(String name, double value) { this.name = name; this.value = value; } @Override public double evaluate() { return value; }}public record Addition(Expression left, Expression right) implements Expression { @Override public double evaluate() { return left.evaluate() + right.evaluate(); }}public record Multiplication(Expression left, Expression right) implements Expression { @Override public double evaluate() { return left.evaluate() * right.evaluate(); }}
// Create instancesShape circle = new Circle(5.0);Shape rectangle = new Rectangle(4.0, 6.0);Shape triangle = new Triangle(3.0, 4.0);// Pattern matching with instanceof (Java 16+)public static double calculateArea(Shape shape) { if (shape instanceof Circle c) { return c.area(); } else if (shape instanceof Rectangle r) { return r.area(); } else if (shape instanceof Triangle t) { return t.area(); } // Compiler knows all cases are covered return 0;}// Switch expressions with pattern matching (Java 17+)public static String describe(Shape shape) { return switch (shape) { case Circle c -> "Circle with radius " + c.radius; case Rectangle r -> "Rectangle with dimensions " + r.width + "x" + r.height; case Triangle t -> "Triangle with base " + t.base + " and height " + t.height; // Compiler ensures exhaustiveness };}// Expression evaluationExpression expr1 = new Constant(5.0);Expression expr2 = new Variable("x", 3.0);Expression expr3 = new Addition(expr1, expr2);Expression expr4 = new Multiplication(expr3, new Constant(2.0));double result = expr4.evaluate(); // (5 + 3) * 2 = 16// Pattern matching on expressionspublic static String format(Expression expr) { return switch (expr) { case Constant c -> String.valueOf(c.value()); case Variable v -> v.name(); case Addition a -> "(" + format(a.left()) + " + " + format(a.right()) + ")"; case Multiplication m -> "(" + format(m.left()) + " * " + format(m.right()) + ")"; };}
Comments
No comments yet. Be the first to comment!
Please login to leave a comment.