Sealed Classes (Java 17+)
Teil des Abschnitts Objektorientierte Programmierung der Java-Journey von Coddy — Lektion 52 von 87.
Im traditionellen Java kann jede andere Klasse eine von Ihnen erstellte Klasse erweitern (es sei denn, Sie markieren sie als final). Aber was ist, wenn Sie Vererbung zulassen möchten, aber nicht für jeden? Java 17 hat sealed classes eingeführt, um Ihnen eine präzise Kontrolle darüber zu geben, welche Klassen Ihre erweitern dürfen.
Eine versiegelte Klasse deklariert ihre zulässigen Unterklassen explizit unter Verwendung der Schlüsselwörter sealed und permits:
sealed class Shape permits Circle, Rectangle, Triangle {
abstract double area();
}
final class Circle extends Shape {
double radius;
double area() { return Math.PI * radius * radius; }
}
final class Rectangle extends Shape {
double width, height;
double area() { return width * height; }
}
final class Triangle extends Shape {
double base, height;
double area() { return 0.5 * base * height; }
}Nur Circle, Rectangle und Triangle können Shape erweitern. Jede andere Klasse, die versucht, sie zu erweitern, wird einen Kompilierungsfehler verursachen.
Jede zulässige Unterklasse muss einen von drei Modifikatoren verwenden: final (keine weitere Erweiterung), sealed (setzt die Einschränkungskette fort) oder non-sealed (öffnet für uneingeschränkte Erweiterung):
sealed class Vehicle permits Car, Truck { }
final class Car extends Vehicle { } // Kann nicht erweitert werden
non-sealed class Truck extends Vehicle { } // Jeder kann Truck erweiternSealed Classes sind besonders leistungsfähig in Verbindung mit Pattern Matching in Switch-Ausdrücken, da der Compiler alle möglichen Subtypen kennt und die Vollständigkeit überprüfen kann. Sie sind ideal für die Modellierung einer festen Menge von Typen innerhalb einer Domäne, wie zum Beispiel Zahlungsmethoden, Antworttypen oder geometrische Formen.
Aufgabe
EinfachLassen Sie uns ein Benachrichtigungssystem bauen, das versiegelte Klassen (sealed classes) demonstriert, indem es einschränkt, welche Arten von Benachrichtigungen in Ihrer Anwendung existieren können. Sie werden eine Hierarchie erstellen, in der nur bestimmte Benachrichtigungstypen zulässig sind und jeder Typ die Zustellung unterschiedlich handhabt.
Sie werden Ihren Code in vier Dateien organisieren:
Notification.java: Erstellen Sie einesealedabstrakte Klasse, die als Basis für alle Benachrichtigungen dient. Sie sollte genau drei Unterklassen zulassen:EmailNotification,SMSNotificationundPushNotification. Ihre versiegelte Klasse benötigt ein geschütztes Feldmessage(String), einen Konstruktor zu dessen Initialisierung, einen Getter für die Nachricht und eine abstrakte Methodedeliver(), die einen String zurückgibt, der beschreibt, wie die Benachrichtigung gesendet wird.EmailNotification.java: Erstellen Sie einefinalKlasse, die Notification erweitert. Eine EmailNotification hat ein zusätzliches privates Feldrecipient(String) for the email address. Ihr Konstruktor sollte sowohl die Nachricht als auch den Empfänger entgegennehmen und den Konstruktor der Elternklasse mitsuper()aufrufen. Die Methodedeliver()sollte Folgendes zurückgeben:Sending email to [recipient]: [message]SMSNotification.java: Erstellen Sie einenon-sealedKlasse, die Notification erweitert – dies ermöglicht es anderen Klassen, sie bei Bedarf in Zukunft zu erweitern. Eine SMSNotification hat ein zusätzliches privates FeldphoneNumber(String). Ihr Konstruktor nimmt die Nachricht und die Telefonnummer entgegen. Die Methodedeliver()sollte Folgendes zurückgeben:Sending SMS to [phoneNumber]: [message]PushNotification.java: Erstellen Sie einefinalKlasse, die Notification erweitert. Eine PushNotification hat ein zusätzliches privates FelddeviceId(String). Ihr Konstruktor nimmt die Nachricht und die Geräte-ID entgegen. Die Methodedeliver()sollte Folgendes zurückgeben:Sending push to device [deviceId]: [message]Main.java: Bringen Sie Ihr Benachrichtigungssystem zusammen! Sie erhalten vier Eingaben: eine Nachricht (String), eine E-Mail-Adresse (String), eine Telefonnummer (String) und eine Geräte-ID (String).Erstellen Sie von jedem Benachrichtigungstyp ein Exemplar unter Verwendung derselben Nachricht, aber der jeweiligen Kontaktinformationen. Speichern Sie alle drei in einem Array vom Typ
Notification[], um Polymorphismus mit versiegelten Klassen zu demonstrieren. Iterieren Sie dann durch das Array und geben Sie das Ergebnis des Aufrufs vondeliver()für jede Benachrichtigung aus.
Sie erhalten vier Eingaben in der folgenden Reihenfolge: Nachricht, E-Mail-Adresse, Telefonnummer und Geräte-ID.
Beachten Sie, wie die versiegelte Klasse die Hierarchie einschränkt – nur die drei zulässigen Klassen können Notification erweitern. Jede Unterklasse muss sich selbst als final, sealed oder non-sealed deklarieren. Dies gibt Ihnen die volle Kontrolle über Ihre Typhierarchie und ermöglicht dennoch Polymorphismus!
Spickzettel
Eine versiegelte Klasse (sealed class) schränkt mithilfe der Schlüsselwörter sealed und permits ein, welche Klassen sie erweitern können:
sealed class Shape permits Circle, Rectangle, Triangle {
abstract double area();
}Nur die in permits aufgeführten Klassen können die versiegelte Klasse erweitern. Jede andere Klasse, die versucht, sie zu erweitern, führt zu einem Kompilierungsfehler.
Jede zulässige Unterklasse muss einen von drei Modifikatoren verwenden:
final– verhindert weitere Erweiterungensealed– setzt die Einschränkungskette mit eigenen zulässigen Unterklassen fortnon-sealed– öffnet die Hierarchie für uneingeschränkte Erweiterungen
sealed class Vehicle permits Car, Truck { }
final class Car extends Vehicle { } // Kann nicht erweitert werden
non-sealed class Truck extends Vehicle { } // Jeder kann Truck erweiternVersiegelte Klassen sind nützlich für die Modellierung einer festen Gruppe von Typen in einer Domäne, wie z. B. Zahlungsmethoden, Antworttypen oder geometrische Formen. Sie funktionieren gut mit Pattern Matching in Switch-Ausdrücken, da der Compiler alle möglichen Untertypen kennt.
Probier es selbst
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Lies die vier Eingaben
String message = scanner.nextLine();
String email = scanner.nextLine();
String phoneNumber = scanner.nextLine();
String deviceId = scanner.nextLine();
// TODO: Erstelle von jedem Benachrichtigungstyp eine Instanz mit derselben message
// - EmailNotification mit message und email
// - SMSNotification mit message und phoneNumber
// - PushNotification mit message und deviceId
// TODO: Speichere alle drei Benachrichtigungen in einem Notification[] Array
// Dies demonstriert Polymorphismus mit sealed classes
// TODO: Iteriere durch das Array und gib das Ergebnis von deliver() aus
// für jede Benachrichtigung
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienEinführung in die OOPKlassen vs. ObjekteDas this-SchlüsselwortMethodenFelder (Attribute)Konstruktor-MethodeKonstruktor-ÜberladungRückblick – Einfacher Taschenrechner4Vererbung
Grundlagen der Vererbung (extends)Das super-SchlüsselwortMethoden überschreiben (@Override)Konstruktor-VerkettungDie Object-KlasseEinfache & mehrstufige VererbungWarum keine Mehrfachvererbung von KlassenZusammenfassung - Mitarbeiter-Hierarchie7Spezielle Methoden & Object-Klasse
toString()-Methodeequals() und hashCode()clone()-MethodecompareTo() und ComparableComparator-InterfaceZusammenfassung – Benutzerdefiniertes Sortieren2Zugriffsmodifikatoren & Kapselung
Überblick über ZugriffsebenenGetter- und Setter-MethodenInformation HidingDas final-SchlüsselwortRückblick – Bankkonto-Manager5Polymorphismus
Grundlagen der MethodenüberladungMethodenüberschreibung (Laufzeit)Upcasting und DowncastingDer instanceof-OperatorAbstrakte Klassen und MethodenZusammenfassung – Formenrechner8Fortgeschrittene OOP-Konzepte
Komposition vs. VererbungAggregation vs. KompositionInnere, geschachtelte & anonyme KlassenEnums und Enum-MethodenRecords (Java 16+)Sealed Classes (Java 17+)11Design Patterns Teil 1
Einführung in Design PatternsSingleton-PatternFactory-PatternBuilder-PatternObserver-PatternStrategy-Pattern14Abschlussherausforderungen
E-Learning-PlattformBanksystemSpielcharakter-EntwicklungFahrzeugvermietung3Klasseneigenschaften & Statische Member
Instanz- vs. statische VariablenStatische MethodenStatische BlöckeKonstanten (static final)Zusammenfassung – Zähler & Utility6Interfaces & Abstrakte Klassen
Einführung in InterfacesInterfaces implementierenImplementierung mehrerer InterfacesDefault- & statische Methoden in InterfacesAbstrakte Klassen vs. InterfacesFunktionale InterfacesZusammenfassung - Zahlungssystem