In Java, by default, there is no restriction on a class
which public
interfaces it can impliment. Since Java 15, now a class or interface can be declared sealed class or sealed interface using the modifier sealed
. It is a preview feature in Java 15.
A sealed class or interface restricts which other classes or interfaces may extend or implement them. Conceptually, it is a more declarative way than access modifiers to restrict the use of a class or interface as a parent class or as a parent interface.
A sealed class is a class or interface that restricts which other classes or interfaces may extend.
1. Sealed Classes
1.1. sealed
modifier and permits
keyword
The sealing of a class or interface can be done using the modifier sealed
in the declaration time. Then, after any extends
and implements
clauses, the permits
clause specifies the classes that are permitted to extend the sealed class.
The reserved keyword permits
lists all the classes that can extend the sealed class directly. The listed subclasses can either be final
, non-sealed, or sealed.
For example, the following declaration of Account
specifies three permitted subclasses:
sealed class Account permits CurrentAccount, SavingAccount, LoanAccount { } final class CurrentAccount extends Account {} non-sealed class SavingAccount extends Account {} sealed class LoanAccount extends Account permits HomeloanAccount, AutoloanAccount {} final class HomeloanAccount extends LoanAccount{} final class AutoloanAccount extends LoanAccount{}
Here, we are permitted only 3 classes the permission to extend the Account
class. No other class class can extend the Account
class.
Similarily, only HomeloanAccount
and AutoloanAccount
are only two supported account types for LoanAccount
.
1.2. final
, sealed
and non-sealed
Subclasses
The permitted subclasses must have exactly one of the following modifiers to describe how it continues the sealing initiated by its superclass:
- final class cannot be extended further.
- sealed class can only be extended by its permitted subclasses.
- non-sealed class can be extended by unknown subclasses as well. A sealed class cannot force the sealing behavior to its permitted subclasses.
1.3. Packaging of sealed classes
- The sealed class and its subclasses, all must be inside the same module.
- If the given module is a unnamed module then all the classes must be inside the same package.
- If the permitted classes are written in the same
.java
file then we can omit thepermits
keyword.public sealed class Account {} //Omits 'permits' keyword final class CurrentAccount extends Account {} non-sealed class SavingAccount extends Account {} sealed class LoanAccount extends Account {} //Omits 'permits' keyword final class HomeloanAccount extends LoanAccount{} final class AutoloanAccount extends LoanAccount{}
1.4. Records as sealed classes
We can have a record class in the permits
clause of a sealed
class or interface.
Record classes are implicitly final
and can be used as subclasses of a sealed class.
1.5. APIs Support
Java has added two new methods to support the usage of sealed classes:
boolean isSealed()
– It returnstrue
if the given class or interface is sealed.
java.lang.constant.ClassDesc[] permittedSubclasses()
- It returns an array of ClassDesc
objects where each object in array represent a subclass of the sealed class.
2. Sealed Interfaces
There are not many differences between how a sealed class is defined vs. how a sealed interface is defined. Like sealed classes, to seal an interface, add the sealed
modifier to its declaration.
Then, after any extends
clause, add the permits
clause which specifies the classes that can implement the sealed interface and the interfaces that can extend the sealed interface.
public sealed interface IReport permits Printable, Formattable, ExcelReport, PdfReport { } non-sealed interface Printable extends IReport {} non-sealed interface Formattable extends IReport {} non-sealed class ExcelReport implements IReport {} non-sealed class PdfReport implements IReport {}
Sealed interfaces follow the same declaration rules as sealed classes.
3. When to use sealed classes?
Remember the use of instanceof operator to test whether the object is an instance of the specified class. Generally, we checked all the possible class types and, at last, in else
block, we have to write some code if the given instance doesn’t match any class type.
Also, there is no guarantee that another developer will add one more class to the hierarchy and add the type check in the given instanceof
checks. Sealed classes can impose this restriction on the hierarchies at the language level.
With the future direction of instanceof
operator and pattern matching, the default
block or else
block will not be needed.
As soon as a new subclass is added to a sealed class, by using type test patterns, the compiler will be able to check that every permitted subclass is covered.
Happy Learning !!