Contents

What are Sealed Classes

Writen by: David Vlijmincx

What are sealed classes and interfaces

Using the sealed modifier gives you greater control over inheritance within Java. By predefining which classes are allowed to extend or implements a sealed class or interface.

When to use sealed

In previous versions of Java, we only had access-modifiers to restrict inheritance, now we can use sealed to decide what code is allowed to implement it. Because sometimes, you want to reuse code only between certain classes.

Creating sealed classes

Java 17 also introduces other modifiers to help you write sealed classes: sealed, non-sealed, and permits.

Sealed Classes

sealed and permit are all you need to create a sealed class. The permit must be at the end, so after the class name and any implements or extends.

1
2
3
sealed class Animal permits Dog, Cat, Bird {

}

The sub-classes of a sealed class must be final, sealed, or non-sealed.

1
2
3
4
5
6
7
final class Dog extends Animal{}

non-sealed class Bird extends Animal{}
class Parrot extends Bird{}

sealed class Cat extends Animal permits HouseCat{}
final class HouseCat extends Cat{}

Non-sealed classes

non-sealed allows the class or interface to be extended or implemented by any other code. Because sometimes, you want specific extension points that others can use.

Making Bird non-sealed Parrot can now extend it without being sealed, non-sealed, or final.

1
2
3
sealed class Animal permits Dog, Cat, Bird {}
non-sealed class Bird extends Animal{}
class Parrot extends Bird{}

Sealed Interfaces

Also, interfaces can be sealed. The permits now give you control over what code can implement or extend it. It works the same as with a class. Interfaces can also be sealed or non-sealed. You cannot use final because then no class could implement the interface.

1
2
3
4
5
6
7
sealed interface Vehicle permits Car, Bus{}

final class Car implements Vehicle{}

sealed interface Bus extends Vehicle{}
final class CityBus implements Bus{}
non-sealed interface TourBus extends Bus{}

Sealed Records

Because records are implicitly final, they are a little more concise.

1
2
3
sealed interface Computer permits Desktop{}

record Desktop(int cores, int ram) implements Computer{}

Patten matching with Switch

The compiler knows all the possible subclasses of a sealed class. This allows you to create a switch without a default case. Because it knows that we covered all the possible subclasses, if the Animal class was not abstract or a subclass was non-sealed, the Switch would need a default case.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
static Animal returnAnimal(Animal animal){
    return switch (animal){
        case Dog dog -> dog;
        case HouseCat houseCat -> houseCat;
        case Cat cat -> cat;
    };
}

sealed abstract class Animal permits Dog, Cat {}
final class Dog extends Animal{}
sealed class Cat extends Animal permits HouseCat{}
final class HouseCat extends Cat{}

Security benefit

Sealed classes that have no non-sealed subclasses also have a security benefit because they have restricted extensibility. For example, the method openSafe(SafeLock lock, String key) accepts a subclass of SafeLock, but a malicious person could create the EvilLock and send the keys somewhere else. A Sealed interface that only permits GoodLock to implement the interface can prevent the EvilLock from being created. Thus preventing malicious people from harming.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
static void openSafe(SafeLock lock, String key){
    lock.open(key);
}

interface SafeLock{
    void open(String key);
}

class GoodLock implements SafeLock{
    @Override
    public void open(String key) {
        System.out.println("Open the lock");
    }
}

class EvilLock implements SafeLock{
    @Override
    public void open(String key) {
        System.out.println("Send key to other user");
    }
}

Conclusion

Sealed classes are a creat new way to restrict inheritance and give the authors more control over their code. The examples covered creating sealed classes, interfaces, records, and how to extend or implement them. We also covered the security benefit they add to a codebase.

Further reading