Java 17 ne aduce câteva lucruri noi printre care și sealed classes. Acestea îmbunătățesc limbajul prin faptul că reprezintă o modalitate de a restricționa accesul la extinderea unei clase. Desigur, aveam pentru aceasta opțiunea marcărilor ca final sau limitările prin modificatorii de acces protected ori private. Avantajul claselor sealed constă în controlarea mai ușoară a cine are dreptul de a o extinde.
Ne permite să definim lista de clase care pot să extindă clasa curentă. Folosim keywordul permits pentru a defini această listă. La rândul lor, clasele copil pot să fie de tipul:
Final class - clasa nu mai poate fie extinsă.
Sealed class - clasa definește la rândul ei lista de clase ce pot să o extindă.
Fig. 1. Sursa: https://learning.oreilly.com/library/view/ocp-oracle-certified/9781119864585/c07.xhtml#R_c07-fig-0005
public sealed class Article
permits TechnicalArticle,
AbstractArticle,
ManagementArticle{}
public final class TechnicalArticle
extends Article{}
public non-sealed class
AbstractArticle extends Article{}
public sealed class ManagementArticle
extends Article permits AgileArticle
public final class AgileArticle
extends ManagementArticle
public class PoliticalArticle
extends AbstractArticle
Fig. 2.
Așa cum se vede în acest exemplu, avem clasa sealed Article
extinsă de TechnicalArticle
(clasă finală), AbstractArticle
este non-sealed, iar prin ea ne apare PoliticalArticle
. Ultima clasă este ManagementArticle
(sealed) extinsă de clasa finală AgilArticle
.
Trebuie menționat că în toată ierarhia, PoliticalArticle
extinde într-un fel nedorit AbstractArticle
. Soluția finală ar putea fi excluderea AbstractArticle
din lista de clase permise. Ideal ar fi însă să putem specifica printr-o adnotare dacă permitem sau nu clase non-sealed în ierarhia Article
.
În cazul în care toate clasele sealed și copii ce o moștenesc sunt în același fișier, menționarea listei permits devine opțională iar definiția acestora devine următoarea:
sealed class Article{}
final class TechnicalArticle
extends Article {}
non-sealed class AbstractArticle
extends Article{}
class PoliticalArticle
extends AbstractArticle{}
sealed class ManagementArticle {}
final class AgileArticle
extends ManagementArticle {}
Putem aplica constrângerile sealed și interfețelor. Diferența față de clase este aceea că în clauza permits vom putea menționa atât alte interfețe ce pot să o extindă pe cea curentă, cât și clase care o pot implementa.
public sealed interface Article
permits TechnicalArticle,
AbstractArticle,
ManagementArticle {}
public final class TechnicalArticle
implements Article {}
public sealed interface ManagementArticle
extends Article permits AgileArticle{}
public final class AgileArticle
implements ManagementArticle{}
public non-sealed interface AbstractArticle
extends Article{}
public final class PoliticalArticle
implements AbstractArticle{}
Singura diferență față de clasele sealed este că o interfață nu poate fi definită final. Interfețele copil pot fi doar sealed sau non-sealed.