導入
Factory Methodのレッスンで作った Shape インタフェースを思い出してください。Circle・Square・Triangle を実装しましたが、理論上は誰でも自由に Shape を実装した新しいクラスを追加できます。それは柔軟である一方、「Shape の実装は全部でいくつあるか」をコンパイラが把握できないという弱点にもなります。Java 17で正式導入された sealed(シールド) は、「継承・実装してよい相手をあらかじめ列挙する」機能です。
説明
sealed を付けたインタフェース・クラスは、permits で許可した相手しか継承・実装できません。
sealed interface Shape permits Circle, Square, Triangle {}
final class Circle implements Shape {
double radius;
}
final class Square implements Shape {
double side;
}
final class Triangle implements Shape {
double base, height;
}
classDiagram
class Shape {
<<sealed interface>>
}
Shape <|.. Circle
Shape <|.. Square
Shape <|.. Triangle
note for Shape "permits Circle, Square, Triangle\nそれ以外は実装できない"
sealed interface Shape permits Circle, Square, Triangle {}…Shapeを実装できるのはCircle・Square・Triangleの3つだけだと、コンパイラに宣言します。他のファイルで勝手に4つ目の実装クラスを作ることはできません。- 各実装クラスは
final(これ以上継承させない)か、sealed(さらに継承先を限定する)か、non-sealed(誰でも継承可能に戻す)のいずれかを明示する必要があります。 - なぜ嬉しいのか。「
Shapeの実装は全部でこの3つ」とコンパイラが保証してくれるので、次のレッスンで見る switchのパターンマッチング と組み合わせたとき、「すべてのケースを網羅しているか」までコンパイラがチェックしてくれます。Factory Methodで「新しい種類を追加するときの変更箇所を1か所にまとめる」工夫をしましたが、sealedは逆に「種類が増えすぎない・想定外の実装が紛れ込まない」ことを保証する道具です。