S-JIS[2021-09-19/2023-09-23] 変更履歴

シールクラス

Javaのシールクラスについて。


概要

Java17(プレビュー版ではJava15〜16)で、sealed class(シールクラス)が使えるようになった。

クラス定義でsealedを付けると、「そのクラスを継承できるクラス」を限定することが出来る。
permitsで継承可能なクラスを指定する。

public abstract sealed class Shape permits Circle, Rectangle, Square {
}

public final class Circle extends Shape {
}

public sealed class Rectangle extends Shape permits TransparentRectangle, FilledRectangle {
}

public non-sealed class Square extends Shape {
}

Java21では、switch文/式にシールクラスを指定することが出来る。[/2023-09-23]
この際、網羅性がチェックされる。(caseで全ての子クラスが指定されているかどうかがチェックされる)

「permits」「sealed」「non-sealed」はcontextual keywordsなので、permits・sealedといった変数名は従来通り使用できる。
(non-sealedはハイフン入りのキーワードなので、変数名としてはそもそも使用できない)


sealed classを直接カタカナに直すと、「シールドクラス」になる。
が、シールドだとshield(盾)をイメージしてしまうので、シールドにはしない方がいいと思う。

個人的には「封印クラス」という訳語を推したいところだが、
Java17のjavacのコンパイルエラーメッセージでは「シール・クラス」になっている。
sealは、あのペタッと貼るシールと同じ言葉らしい。


シールクラスの例

シールクラスの例 備考
public sealed class A permits A1, A2, A3 {
}
シールクラスは、classの前にsealedを付ける。
permitsで、継承を許すクラスを指定する。
public final class A1 extends A {
}
継承する側の子クラスは、final(またはsealedまたはnon-sealed)にする必要がある。
finalになっていないと、「sealed、non-sealedまたはfinal修飾子が必要です」というコンパイルエラーになる。
public sealed class A2 extends A permits A21 {
}

public final class A21 extends A2 {
}
継承する子クラスをsealedにすると、そのクラスからさらに子クラスを限定して作ることが出来る。
public non-sealed class A3 extends A {
}

public class A31 extends A3 {
}
non-sealedを指定する例。
public final class A4 extends A {
}
親クラスでpermits宣言されていないクラスを定義しようとすると、
「クラスはシール・クラスAを拡張できません」というコンパイルエラーになる。

switchでシールクラス

Java21以降(プレビュー版ではJava15〜20)では、シールクラスをswitch文・式で指定することが出来る。[2023-09-23]

sealed interface S permits A, B, C {}
final class A implements S {}
final class B implements S {}
record C(int i) implements S {} // Implicitly final

	static int testSealedCoverage(S s) {
		return switch (s) {
			case A a -> 1;
			case B b -> 2;
			case C c -> 3;
		};
	}

この際、網羅性チェックが行われる。
(caseでシールクラスの全てのサブクラスが指定されていないとコンパイルエラーになる。もちろんdefaultがあれば問題ない)


Java目次へ戻る / 新機能へ戻る / 技術メモへ戻る
メールの送信先:ひしだま