* Ограничено наследими (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) ще е имплементиращият/наследяващият клас, компилатора ще даде грешка.
Добави коментар