Sealed Classes in Java: A Complete Guide for Beginners
In the world of Java programming, encapsulation, inheritance, and polymorphism form the foundation of Object-Oriented Programming (OOP). With each new Java release, the language continues to evolve to meet modern software development needs. One such significant addition is sealed classes, introduced in Java 15 as a preview feature and officially rolled out in Java 17 LTS.
In this blog post, we'll explore:
-
What are Sealed Classes?
-
Why were Sealed Classes introduced?
-
How to use Sealed Classes with examples
-
Advantages of using Sealed Classes
-
Key points and restrictions
-
Comparison with other access controls
-
Common mistakes and best practices
Let's dive deep into the concept of sealed classes in Java!
What are Sealed Classes in Java?
A sealed class is a special type of class in Java that restricts which other classes or interfaces can extend or implement it.
In simpler words, when you declare a class as sealed
, you explicitly specify the permitted subclasses.
This gives you better control over inheritance and enhances security and design clarity.
🔹 Syntax Overview:
public sealed class Shape permits Circle, Rectangle, Square {
// fields and methods
}
Here, only Circle
, Rectangle
, and Square
are allowed to extend Shape
. No other class can extend it.
Why Were Sealed Classes Introduced?
Before Java 15, developers had limited control over the inheritance hierarchy:
-
Any class could extend your class unless you marked it
final
. -
If you wanted to allow some specific subclasses but prevent others, there was no direct way.
This led to several problems:
-
Security risks: Unauthorized classes extending your core classes.
-
Design issues: Poorly managed inheritance trees.
-
Maintenance challenges: Unpredictable extensions over time.
Sealed classes provide a middle ground between final
classes (which cannot be extended) and normal classes (which can be extended freely).
How to Create Sealed Classes in Java
Sealed classes involve three new keywords:
-
sealed
-
non-sealed
-
permits
Let’s go step-by-step.
1. Defining a Sealed Class
public sealed class Vehicle permits Car, Bike {
// Common functionality
}
The permits
clause lists the classes allowed to extend Vehicle
.
2. Extending a Sealed Class
Each permitted subclass must explicitly declare itself as either:
-
final
— cannot be further extended. -
sealed
— can be further sealed. -
non-sealed
— open for unrestricted extension.
🔸 Example:
public final class Car extends Vehicle {
// Car specific functionality
}
public non-sealed class Bike extends Vehicle {
// Bike specific functionality
}
Here:
-
Car
isfinal
— no one can subclassCar
. -
Bike
isnon-sealed
— anyone can subclassBike
.
A Full Example with Sealed Classes
// Sealed Class
public sealed class Shape permits Circle, Rectangle, Triangle {
public abstract double area();
}
// Permitted Subclasses
public final class Circle extends Shape {
private double radius;
public Circle(double radius) {
this.radius = radius;
}
@Override
public double area() {
return Math.PI * radius * radius;
}
}
public sealed class Rectangle extends Shape permits Square {
private double length;
private double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
@Override
public double area() {
return length * width;
}
}
// Rectangle is sealed, permits Square
public final class Square extends Rectangle {
public Square(double side) {
super(side, side);
}
}
public non-sealed class Triangle extends Shape {
private double base;
private double height;
public Triangle(double base, double height) {
this.base = base;
this.height = height;
}
@Override
public double area() {
return 0.5 * base * height;
}
}
Advantages of Using Sealed Classes
✅ Better Control over inheritance: Only specific classes can extend.
✅ Improved Security: Prevents unexpected subclassing.
✅ Enhanced Code Readability: Clear understanding of allowed hierarchies.
✅ Stronger API Contracts: Ensures limited and known types in public APIs.
✅ Easier Maintenance: When refactoring, you know exactly where extensions occur.
Key Points and Restrictions
-
All permitted subclasses must reside in the same module or package.
-
Every permitted subclass must explicitly declare itself as
sealed
,non-sealed
, orfinal
. -
If a sealed class is not extended as intended, the code will not compile.
-
Sealed classes can be:
-
Abstract
-
Concrete
-
Interfaces (Yes! Interfaces can also be sealed)
-
🔹 Example of Sealed Interface:
public sealed interface Operation permits Addition, Subtraction {
int apply(int a, int b);
}
Sealed vs Final vs Abstract Classes
Feature | Final Class | Abstract Class | Sealed Class |
---|---|---|---|
Extendable? | ❌ No | ✅ Yes | ✅ Limited |
Purpose | Prevent inheritance | Define incomplete behavior | Restrict inheritance |
Subclass Control | Full restriction | No control | Partial control |
Common Mistakes to Avoid
🚫 Forgetting to specify sealed
, final
, or non-sealed
in subclasses.
🚫 Permitting subclasses from a different package without proper configuration.
🚫 Using sealed classes when a simple final
would suffice — don't overcomplicate.
Best Practices
✔️ Use sealed classes only when needed to restrict inheritance.
✔️ Group permitted classes logically in the same package or module.
✔️ Document your hierarchy clearly for future maintainers.
✔️ Prefer readability over over-engineering.
Conclusion
Sealed Classes are a powerful addition to Java's toolbox, offering a new way to design safe, predictable inheritance hierarchies. They strike a perfect balance between flexibility and control.
If you're building large applications, public APIs, or security-critical software, sealed classes can make your code more secure, clearer, and easier to maintain.
Now that you've learned about sealed classes, why not try creating your own mini project using them?
Happy Coding! 🚀
Sign up here with your email
ConversionConversion EmoticonEmoticon