* Ограничено наследими (sealed) класове
Публикувано на 29 май 2023 в раздел ПИК3 Java.
Преди Java 17 в езика се следваше подход за наследяване, в който или всеки интерфейс/клас може да бъде разширяван (наследяван) от всеки с extends, или това е забранено чрез ключова дума final. С включването на новата ключова дума sealed се въвеждат ограничено наследими класове. Те дават разрешителен списък, с който се изреждат ограничено количество интерфейси/класове от същия пакет, които могат да имплементират/наследяват текущия.
Нека разгледаме следния пример. Ще дефинираме интерфейс „четириъгълник“ и ще реализираме негови реализации „правоъгълник“ и „успоредник“.
package figures2d; abstract interface Quadrilateral{ double getArea(); double getPerimeter(); } record Rectangle (double sideA, double sideB) implements Quadrilateral{ @Override public double getArea(){ return sideA*sideB; } @Override public double getPerimeter(){ return 2*sideA+2*sideB; } } record Parallelogram (double sideA, double sideB, double angle) implements Quadrilateral{ @Override public double getArea(){ return sideA*sideB*Math.sin(angle); } @Override public double getPerimeter(){ return 2*sideA+2*sideB; } }
Тук никой не ни спира да направим например клас „равностранен триъгълник“, който имплементира „четириъгълник“ - това би било напълно нелогично и нежелано, но все пак е възможно. С ключова дума sealed защитаваме интерфейса така, че изреждаме само и единствено класовете, които имат право да го имплементират:
sealed interface Quadrilateral permits Rectangle, Parallelogram{ double getArea(); double getPerimeter(); } record Rectangle (double sideA, double sideB) implements Quadrilateral{ @Override public double getArea(){ return sideA*sideB; } @Override public double getPerimeter(){ return 2*sideA+2*sideB; } } record Parallelogram (double sideA, double sideB, double angle) implements Quadrilateral{ @Override public double getArea(){ return sideA*sideB*Math.sin(angle); } @Override public double getPerimeter(){ return 2*sideA+2*sideB; } }
Вече няма да можем да правим нови класове с имплементации на интерфейса Quadrilateral.
В случая използваме record, с което скриваме част от важните ограничения - класът, който имплементира защитения интерфейс или наследява защитен клас трябва изрично да окаже от своя страна дали е или final (ненаследим), sealed (частично наследим) или свободен (non-sealed). Следният пример демонстрира това:
sealed interface Quadrilateral permits Parallelogram{ double getArea(); double getPerimeter(); } sealed class Parallelogram implements Quadrilateral permits Rectangle{ double sideA; double sideB; double angle; public Parallelogram(double sideA, double sideB, double angle){ this.sideA = sideA; this.sideB = sideB; this.angle = angle; } @Override public double getArea(){ return sideA*sideB*Math.sin(angle); } @Override public double getPerimeter(){ return 2*sideA+2*sideB; } } sealed class Rectangle extends Parallelogram permits Square{ public Rectangle(double sideA, double sideB){ super(sideA, sideB, Math.PI/2); } } final class Square extends Rectangle{ public Square(double side){ super(side, side); } }
Ако не се посочи какъв тип (sealed, non-sealed или final) ще е имплементиращият/наследяващият клас, компилатора ще даде грешка.
Добави коментар