Java 17: Sealed Classes and Interfaces (JEP 409)
Control the inheritance

I am a developer who loves Java, Spring, Quarkus, Micronaut, Open source, Microservices, Cloud
Search for a command to run...
Control the inheritance

I am a developer who loves Java, Spring, Quarkus, Micronaut, Open source, Microservices, Cloud
No comments yet. Be the first to comment.
Spring AI Tool Calling: From Chatbot to AI Agent with @Tool Your AI is smart. It knows an enormous amount. But it's frozen. It doesn't know what time it is right now. It doesn't know what's on your ca
Spring AI Advisors API Explained Series: Spring AI Complete Course — Lecture 4 of 12Reading Time: 8 minutesLevel: Intermediate Most developers stop at ChatClient. That is enough for demos. It is not
Working with Multiple AI Models in Spring AI Spring AI Complete Course — Lecture 3 of 12Previous: Lecture 2 — ChatClient API | Next: Lecture 4 — Advisors API In production AI applications, you rarel
Spring AI ChatClient API: The Fluent Heart of AI Integration Introduction If you've ever tried integrating AI models into a Java application, you know the pain. HTTP clients, API keys scattered everywhere, vendor-specific SDKs that never quite fit. W...
What is Spring AI? — Why Java Developers Need This in 2026 Every AI tutorial you see is in Python. LangChain, LlamaIndex, OpenAI SDK — all Python. But here's the uncomfortable truth: 80% of enterprise backends run Java. So who's building AI into thos...
Sealed Classes are an important new feature introduced as a preview feature of JDK 15 and 16 but as a permanent candidate in JDK 17 (LTS). It helps you to have a finer controller over class hierarchy. Inheritance is the main pillar for OOPS but if we see the current framework, it can easily be misused. Any class can extend another unless it's not final. What if you as a developer want to allow few classes to extend it but not all. Sealed classes come to rescue you.
Let us look at sealed classes and their usage.
Do note that if you want to use sealed classes you must have JDK 15 + on the classpath.
We will create a class Character and permit only Hero and Villain to extend it. We will also create child clesses of Hero and Villain
Below is the structure we will follow

package sealed;
public sealed class Character permits Hero, Villan {
public boolean hasPositiveVibes() {
return true;
}
}
We have added a method hasPositiveVibes just to demonstrate the usage. We will Override it in Villan class to send negative vibes. :)
Let us create Hero and Villain in the same package. Do note that any class permitted by a sealed class must be in the same package or else it will give the compilation error.
package sealed;
import sealed.Character;
import sealed.JusticeHammer;
import sealed.WhiteClaw;
public sealed class Hero extends Character permits WhiteClaw, JusticeHammer {
}
Here Hero is again a sealed class and imposing us to tell all those allowed classes. Any class extending from a sealed class must be defined sealed, non-sealed or final.
sealed : Allows limited set classes to extend itselfnon-sealed: Allows any other class to extendfinal: Allows noneWe can now have Whileclaw and JusticeHammer as a final class.
package sealed;
public final class WhiteClaw extends Hero {
}
package sealed;
public final class JusticeHammer extends Hero {
}
Now let us see an example of a non-sealed class. As we know that there are very few real heroes in the world fighting for a cause to so many bad guys. We can't allow everyone to be believed as Hero so we kept a tight control at Hero class and giving permission to only a few. There are many Villains who can break the law, so we have kept Villan as non-sealed.
Do note that we need not define the permit clause with `non-sealed classes. The classes extending to non-sealed can be in different packages as well
We also have overridden the hasPositiveVibes method of Character to send negative vibes from Villain(s)
package sealed;
public non-sealed class Villain extends Character {
@Override
public boolean hasPositiveVibes(){
return false;
}
}
public class Outlaw extends Villain {
}
public class MrKiller extends Villain {
}
Villains don't follow any order, they want to expand beyond earth. Mars is their first target. MrKiller has a son who now lives on Mars, he is MartianKiller. Let us create a package outside the sealed World.
package mars;
import sealed.MrKiller;
public class MartianKiller extends MrKiller {
}
Wait, there is something wrong, World is not only about superheroes and Villains but also about (Humans) Man, Women, and a few who don't want to reveal their identity in this chaotic order.
Let us add Human as Character. Now our Character looks like
public sealed class Character permits Hero, Villain,Humans {
public boolean hasPositiveVibes() {
return true;
}
}
Also, let us look at Humans
package sealed;
/*
permits' clause has been removed as its permitted
classes have been defined in the same file.
*/
public sealed class Humans extends Character {
}
final class Man extends Humans {
}
final class Woman extends Humans {
}
Now MartianKiller and Outlaw are Villains. At this point, we can test our code. Below Main class will create instances of Hero and Villian and test if they send positive or negative vibes.
package sealed;
public class Main {
public static void main(String[] args) {
Character killer= new MartianKiller();
System.out.println(killer.hasPositiveVibes());
Character claw= new WhiteClaw();
System.out.println(claw.hasPositiveVibes());
}
}
The output will be false and true.
TL;DR
I hope this article helped you to understand sealed classes. Sealed interfaces are following the same principles as the sealed classes. If you liked the article, do let me know using a comment or you can share it with your friends.