Java - Sealed Classes and Interfaces

Hello there, future Java developers! Today, we're going to embark on an exciting journey into the world of Sealed Classes and Interfaces in Java. Don't worry if you're new to programming - we'll start from the basics and work our way up. So, grab a cup of coffee (or your favorite beverage), and let's dive in!

Java - Sealed Classes

What are Sealed Classes and Interfaces?

Imagine you're building a treehouse and you want to control who can add rooms to it. That's essentially what sealed classes and interfaces do in Java - they allow you to control which classes can extend or implement them. It's like having a VIP list for your code!

The Problem Sealed Classes Solve

Before we had sealed classes, anyone could extend your class or implement your interface. It was like throwing a party and not knowing who might show up! Sealed classes give you that guest list control.

How to Create a Sealed Class

Let's start with a simple example:

public sealed class Animal permits Dog, Cat, Bird {
    // Animal class code here
}

In this example, Animal is our sealed class. The permits keyword is like our bouncer, only allowing Dog, Cat, and Bird classes to extend Animal.

Extending a Sealed Class

Now, let's see how we can create classes that extend our Animal class:

public final class Dog extends Animal {
    // Dog class code here
}

public final class Cat extends Animal {
    // Cat class code here
}

public non-sealed class Bird extends Animal {
    // Bird class code here
}

Notice the keywords final and non-sealed. These are important:

  • final: This means the class can't be extended further. It's like saying, "The party stops here!"
  • non-sealed: This allows the class to be extended by any other class. It's like saying, "Come on in, the more the merrier!"

Sealed Interfaces

Just like classes, interfaces can also be sealed. Here's an example:

public sealed interface Vehicle permits Car, Motorcycle, Bicycle {
    // Vehicle interface code here
}

And here's how we implement this interface:

public final class Car implements Vehicle {
    // Car class code here
}

public final class Motorcycle implements Vehicle {
    // Motorcycle class code here
}

public non-sealed class Bicycle implements Vehicle {
    // Bicycle class code here
}

Why Use Sealed Classes and Interfaces?

  1. Type Safety: You know exactly which classes can extend or implement your sealed class or interface.
  2. Better Design: It helps you create a more structured and intentional class hierarchy.
  3. Pattern Matching: It works great with pattern matching in switch expressions (a topic for another day, but trust me, it's cool!).

Real-World Example

Let's create a more complex example. Imagine we're building a simple game with different types of characters:

public sealed abstract class GameCharacter permits Warrior, Mage, Archer {
    protected String name;
    protected int health;

    public GameCharacter(String name, int health) {
        this.name = name;
        this.health = health;
    }

    public abstract void attack();
}

public final class Warrior extends GameCharacter {
    public Warrior(String name) {
        super(name, 100);
    }

    @Override
    public void attack() {
        System.out.println(name + " swings a mighty sword!");
    }
}

public final class Mage extends GameCharacter {
    public Mage(String name) {
        super(name, 75);
    }

    @Override
    public void attack() {
        System.out.println(name + " casts a powerful spell!");
    }
}

public non-sealed class Archer extends GameCharacter {
    public Archer(String name) {
        super(name, 80);
    }

    @Override
    public void attack() {
        System.out.println(name + " fires a precise arrow!");
    }
}

In this example, we've created a sealed abstract class GameCharacter with three permitted subclasses: Warrior, Mage, and Archer. Each subclass has its own implementation of the attack() method.

Let's see how we can use these classes:

public class Game {
    public static void main(String[] args) {
        GameCharacter[] characters = {
            new Warrior("Conan"),
            new Mage("Gandalf"),
            new Archer("Legolas")
        };

        for (GameCharacter character : characters) {
            character.attack();
        }
    }
}

When you run this code, you'll see:

Conan swings a mighty sword!
Gandalf casts a powerful spell!
Legolas fires a precise arrow!

Conclusion

Sealed classes and interfaces are powerful tools in Java that allow you to create more controlled and intentional class hierarchies. They're like the bouncers of your code, ensuring only the right classes get to join the party!

Remember, programming is all about solving problems and creating structure. Sealed classes and interfaces are just another tool in your toolbox to help you write cleaner, more maintainable code.

Keep practicing, keep coding, and most importantly, have fun! Before you know it, you'll be sealing classes like a pro. Until next time, happy coding!

Method Description
permits Specifies which classes are allowed to extend a sealed class or implement a sealed interface
sealed Declares a class or interface as sealed
non-sealed Allows a subclass of a sealed class to be extended by any class
final Prevents a class from being extended further

Credits: Image by storyset