sealed classのコードトレース
通知の種類を表すNotice階層を変更しながら、どの宣言でコンパイルが止まるかを調べます。許可リスト・直接の継承関係・子の修飾子・配置の四点を順番に検査し、最小の修正を選びます。Java SE 17を前提にします。
この単元で学ぶこと
- sealedとfinalの違いを説明できる
- 許可された直接の子と間接の子を区別できる
- 修飾子・permits・配置からコンパイル可否を判断できる
本文解説
基準となる宣言 次の三宣言を一つのNotice.javaへ保存します。 sealed class Notice permits Mail, Alert {} final class Mail extends Notice {} non-sealed class Alert extends Notice {} javac --release 17 Notice.javaでコンパイルできる基準例です。三型はいずれもpublicなトップレベル型ではないため、同じファイル内に置けます。
変更1:許可のない直接の子 final class Sms extends Notice {}だけを追加すると失敗します。NoticeのpermitsへSmsを追加すれば、Smsはfinalを持ち配置条件も満たすためこの問題は解消します。子がfinalであることだけでは親の許可は得られません。
変更2:枝をさらに伸ばす class Urgent extends Alert {}は追加できます。Alertはnon-sealedで制限を解除した枝だからです。一方class SpecialMail extends Mail {}はMailがfinalなので追加できません。NoticeのpermitsにSpecialMailを追加しても、finalな直接の親Mailの制約は消えません。
変更3:Alertも限定する Alertをsealed class Alert extends Notice permits Urgent {}へ変更するなら、Urgentをfinal class Urgent extends Alert {}などにします。Alert側で許可し、Urgent側でその先の方針を指定する二条件が必要です。Noticeの許可一覧はAlertまでで足り、間接の子Urgentを含めません。
変更4:子をabstractにする abstract class Alert extends Notice {}だけでは、直接の子の方針が不足します。abstract non-sealed class Alert extends Notice {}なら、インスタンス化は禁じつつ継承制限を解除できます。abstract sealed class Alertなら、その子の許可と方針も整備します。
変更5:permitsを省略する 同じソースファイル内にMailとAlertの宣言がある基準例なら、Noticeのpermitsを省略して直接の子を推論できます。Noticeだけを別ファイルへ分け、MailとAlertを別コンパイル単位へ移したなら、元と同じように省略できるとは限りません。同一パッケージという配置条件と推論可能な範囲は別です。
変更6:インタフェースとrecord sealed interface Message permits Text {}とrecord Text(String body) implements Message {}は許されます。Textは暗黙にfinalです。Messageを直接拡張するインタフェースを追加する場合はsealedかnon-sealedを使い、final interfaceとは書きません。
検証の順番 変更は一回に一つとし、まず基準例が成功することを確認します。失敗したら、直接の親を特定→親の許可→子の方針→module/package配置の順で調べます。コンパイルしたから継承階層の業務設計まで適切とは限りませんが、少なくとも宣言の制約を満たすかを分離して確認できます。
図解
重要ポイント
- permitsは直接の子の一覧であり、継承宣言を代行しない。
- 子はfinal・sealed・non-sealedでその先の方針を決める。
- non-sealedの先は通常の継承規則へ戻る。
- 名前付きモジュールと名前なしモジュールでは配置条件が異なる。
間違えやすい点
- abstractをfinal・sealed・non-sealedの代わりにしない。
- 同じパッケージだけを理由にpermitsを省略しない。
- sealedを暗黙のabstractや暗黙のfinalと考えない。
用語解説
- sealed
- 直接の子となれる型を限定する修飾子。
- permits
- sealed型が許可する直接の子を列挙する節。
- non-sealed
- sealedな親から受けた継承制限をその枝で解除する修飾子。
- 直接の子
- 間に別の型を挟まず、その型を継承または実装する型。
- コンパイル単位
- 一つのソースファイルに相当する宣言のまとまり。
関連教材
参考資料
教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。
確認問題の出題・採点や学習履歴の保存にはログインが必要です。