Java 15 - Sealed Classes Preview Feature (JEP 360)
Java is missing various “hot” features from more modern JVM languages like Scala or Kotlin. One feature it's missed until the release of JDK15 (with JEP 360) is sealed classes. Although the title of JEP is about sealed class, but it's applicable to interface too.
Sealed Class and Interface
Sealed classes and interfaces used to restrict another class from extend or implement the class.
A class or interface is sealed by using sealed
keyword in its declaration, then at the end using permits
keyword and specifies all classes that are permitted to inherits this sealed class. As example, we have two sealed
'classes', one class called Printer
and another one is an interface called Printable
. All examples under package com.dariawan.jdk15.sealed:
public sealed class Printer permits LaserPrinter, InkjetPrinter { } public sealed interface Printable permits LaserPrinter, ThermalPrinter { }
To make the sample more interesting, I also added one parent class which is not a sealed class:
public class NotSealedParent { }
To extends or inherits those two sealed classes, we create LaserPrinter
, InkjetPrinter
, and ThermalPrinter
. Inherited classes expecting non-sealed
, final
, or another sealed
modifiers:
non-sealed
: allowed this class as a parent class, can be extended by any subclassesfinal
: prevent this class as a parent class, cannot be extended further. To refresh the understanding about final keyword, please read Inheritance in Java.sealed
: allowed this class as a parent class that only can be extended by its permitted subclasses.
public final class LaserPrinter extends Printer implements Printable { } public non-sealed class InkjetPrinter extends Printer { } public class InkjetPhotoPrinter extends InkjetPrinter { } public final class ThermalPrinter extends NotSealedParent implements Printable { }
As example for inherits non-sealed
parent class, class InkjetPhotoPrinter
is extended from class InkjetPrinter
.
Class that is not permitted by as sealed class will get a compilation error when tries to extend it. Below ThermalPrinter
compilation will resulted in following error: class is not allowed to extend sealed class: com.dariawan.jdk15.Printer, if we extends from Printer:
public final class ThermalPrinter extends Printer implements Printable { }
Changes in java.lang.Class<T>
Java’s Reflection API also extended to add support for sealed classes. There are two new methodsassociated with sealed classes:
- boolean isSealed(): returns
true
if this 'class' is sealed class or interface. - ClassDesc[] permittedSubclasses(): if it is a sealed class, returns a
ClassDesc
array containing subclasses permitted to extend or implement this class or interface.
Let's check below example to use these new API:
package com.dariawan.jdk15.sealed;
import java.lang.constant.ClassDesc;
public class SealedClassExample {
public static void main(String[] args) {
System.out.println("Printer is sealed: " + Printer.class.isSealed());
System.out.println("Printer permittedSubclasses:");
for (ClassDesc cd : Printer.class.permittedSubclasses()) {
System.out.println(cd.toString());
}
System.out.println("Printable is sealed: " + Printable.class.isSealed());
System.out.println("Printable permittedSubclasses:");
for (ClassDesc cd : Printable.class.permittedSubclasses()) {
System.out.println(cd.toString());
}
System.out.println("NotSealedParent is sealed: " + NotSealedParent.class.isSealed());
System.out.println("NotSealedParent permittedSubclasses:");
for (ClassDesc cd : NotSealedParent.class.permittedSubclasses()) {
System.out.println(cd.toString());
}
System.out.println("LaserPrinter is sealed : " + LaserPrinter.class.isSealed());
System.out.println("LaserPrinter superclass: " + LaserPrinter.class.getSuperclass());
System.out.println("ThermalPrinter is sealed : " + ThermalPrinter.class.isSealed());
System.out.println("ThermalPrinter superclass: " + ThermalPrinter.class.getSuperclass());
}
}
Run the program, here the result:
Printer is sealed: true Printer permittedSubclasses: ClassDesc[LaserPrinter] ClassDesc[InkjetPrinter] Printable is sealed: true Printable permittedSubclasses: ClassDesc[LaserPrinter] ClassDesc[ThermalPrinter] NotSealedParent is sealed: false NotSealedParent permittedSubclasses: LaserPrinter is sealed : false LaserPrinter superclass: class com.dariawan.jdk15.sealed.Printer ThermalPrinter is sealed : false ThermalPrinter superclass: class com.dariawan.jdk15.sealed.NotSealedParent