JEP 409 Classes scellées
Contexte
Je vous avais présenté la fonctionnalité au moment de la sortie du JDK 16. Cette fonctionnalité était en mode Aperçu. Maintenant que c’est en standard dans le langage, profitons pour regarder cela de plus prêt.
Aucune modification a été apporté par rapport à la JEP 397 Sealed classes (Second Preview)
Principe
Le but est d’enrichir l’héritage afin d’amener plus de contrôle. En effet, actuellement, nous avons uniquement le mot clé final
. Cela permet de bloquer l’héritage. Donc, nous ne peuvons pas avoir des classes dérivées.
package fr.exemple.;
public final class Forme {
...
}
public final class Rectangle extends Forme { // Erreur de compilation
...
}
Les classes scellées sont un moyen pour le développeur d’avoir plus de contrôle. Pour cela, nous avons deux nouveaux mot clés sealed
et non-sealed
:
-
sealed
: permet d’avoir des classes dérivées à condition qu’elles fassent partir des classes autorisées pour cela il y a le mot clépermits
à utiliser. -
non-sealed
: permet de ne pas limiter les classes dérivées.
Par exemple, nous avons :
package fr.exemple.geometrie;
public abstract sealed class Forme
permits Cercle, Rectangle {
...
}
Nous définissons une classe abstraite Forme
dont seules les classes Cercle
et Rectangle
sont autorisées comme classes dérivées.
Par conséquent, si le développeur essaie d’écrire l’héritage pour une autre classe. Cela provoquera une erreur de compilation si nous essayons.
package fr.exemple.geometrie;
public class Triangle extends Forme { // Erreur de compilation
...
}
Précision pour le mot-clé permits
Si les classes dérivées sont dans le même fichier. Le mot clé permits
n’est pas nécessaire.
package fr.exemple.geometrie;
public abstract sealed class Forme {
...
public final class Cercle extends Forme {
...
}
public non-sealed class Rectangle extends Forme {
...
}
}
Précision pour le mot-clé non-sealed
Du fait que nous avons précisé que la classe Rectangle
n’est pas scellée. Nous pouvons hériter de cette classe. Par exemple, nous pouvons avoir la classe Carré
définie ainsi :
package fr.exemple.geometrie;
public final class Carre extends Rectangle {
...
}
Interfaces
Cela fonctionne aussi avec les interfaces
package fr.exemple.geometrie;
public sealed interface Forme
permits Cercle, Rectangle, Carre {
...
}
Enregistrements
Les enregistrements peuvent être utilisés pour l’héritage.
Pour rappel, les enregistrements sont des classes. Elles ne peuvent pas hérités d’autres classes (puisque héritage vers Record
) mais elles peuvent implémenter une ou plusieurs interfaces.
Ci dessous un exemple avec les enregistrements :
public sealed interface Noeud
permits Noeud.Feuille, Noeud.Multiplication, Noeud.Addition {
public double eval();
public record Feuille(double val) implements Noeud {
public double eval() {
return val;
}
}
...
}
J’avais utilisé cet exemple lors de conférence sur les nouveautés de Java 16. Le code complet de cet exemple est disponible sur mon github.
Exemple d’utilisation
Cela sera peut-être plus utile pour les personnes qui développent des librairies afin de maitriser les classes et éviter que certains classes soient étendues.
Le JDK prévoit son utilisation par exemple pour protéger certaines interfaces. Par exemple, l’interface ClassDesc où la javadoc indique clairement son usage quand les classes scellées seront disponibles en standard.
Moteur de recherche
"Eduquer, ce n'est pas remplir des vases mais c'est d'allumer des feux." - Michel Montaigne
Billets récents
- Eclipse plante systématiquement sous Debian (et autres distribution Linux)
- JEP 463, Implicitly Declared Classes and Instance Main Methods (Second Preview)
- Debian - Montée de version de Debian 11 (Bullseye) à Debian 12 (Bookworm)
- JEP 451, Prepare to Disallow the Dynamic Loading of Agents
- JEP 444, Virtual Threads