Java Sealed Class

Jeff Li
5 min readDec 10, 2021

The Sealed class has been previewed for two released versions, Java 15 and Java16, and it is finalized in Java 17. Here we are going to have a look at this new feature.

What is the Sealed Class

A sealed class or interface can be extended or implemented only by those classes and interfaces permitted to do so. — by Oracle Doc

Simply put, the class or interface that is sealed can specify the classes that can extend or implement it.

If there is any class that extends the sealed class without being permitted, you get a compile-err.

So, with the sealed class, developers can have more control over their classes’ inheritance hierarchy.

Why do we need the Sealed Class

When declaring a Java class, we always face the problem: who can access the class?

At the top level, Java has two different access controls: public and package-private(of course you can have more options for Nested Class, like protected or private, but it is not a top-level class). However, with access control alone, it is sometimes not enough to model our code cos if the class or interface is accessible to a certain module it can also be extended or implemented by the code in that module.

But in many scenarios, we expect a class can be accessible widely but it can not be extended by other classes as it is designed. That is why we need to introduce more concepts, like final, to achieve our goal, which is more expressive.

However, if a class is modified by the final keyword, that class can not be extended by any class. It runs into the extreme. What if we want a class that can only be extended by the given set of classes? This scenario is kind of common, especially for library designers. Like, you design a class in your module and it should be visible to all others but it can only be extended by the classes in your own module in order to prevent the protected code from being accessed arbitrarily. We want something like “almost final”.

So here the sealed class comes. The sealed class can specify who is able to implement or extend it by using the permit keyword. Like:

So, essentially, the sealed class introduces more control over the class inheritance.

When to use the sealed class

At the first glance, the sealed classes and enum classes share some similar traits: they both have a given set of elements: when being declared, the sealed classes need to specify their restricted subclasses while the enum classes need to specify their restricted values.

However, the key difference is each value in an enum class is a single instance while each subclass from a sealed class can have multiple instances.

Simply put, the enum class represents a fixed set of values while the sealed class represents a fixed set of types of values.

Here is an example to demonstrate the usage of the sealed class:

Google is the owner of the brand Google Pixel and there are several different types of devices in the Google Pixel series. To simplify the case, here we assume Google is at a very early stage and there are only two types: Pixel 1 and Pixel2. We want to model our code for this scenario.

What we can learn is there are two really important principles that we must keep in this case:

  1. Only Google can develop the Google Pixel phones and other people are not legal to do that;
  2. The Google Pixel has limited types of devices and each type of device can have more than one instance so that it can sell to more than one customer.

Approach#0:

Let’s do it in a really naive method:

It is a very simple way to code. However, since the GooglePixel is a public class, it can be extended by anyone. So it violates the first principle. Also, it can potentially have infinite subclasses. Accordingly, there are no constraints that can make sure the second principle is valid.

Approach#1:

Here we model this scenario by enum class.

Now, the GooglePixel can not be extended by anyone else and we can easily know there are only two types of devices in the market. However, since the value in the enum class is a single instance, there is only one device for each type in the market. So it violates the second principle.

Approach#2:

Let’s have a try on the sealed class.

This model expresses clearly that no one but these permitted classes can extend GooglePixel and there are only two types of devices in the market. It looks good!

Of course, you can use some tricks to achieve the goal without the sealed class. Like, let the GooglePixel class be package-private and Pixel1, Pixel2 extend it in the same package:

However, it is not complete protection cos developers can still create the new subclasses in that package at runtime. Additionally, the GooglePixel can not be accessed by other packages, even though these packages belong to your module. Since the GooglePixel is a kind of important concept, it is likely required by other packages and modules.

Summary

Here we only talk about the main idea of the sealed class from a high level. As we discussed, the sealed class can tell its reader and Java compiler clearly that its developer is trying to model the code where the superclass only has a given set of subclasses, which makes sure type-safety at compile time and prevents your code from being violated by unexpected subclasses.

Also, the sealed class is an important foundation for pattern matching that is coming soon. Hope you enjoy it!

--

--