If I read the JLS §8.1.6
and §9.1.4
, correctly the classes that a sealed class/interface permits, are just the direct sub classes/interfaces.
Each sealed class or interface needs to specify at least one direct permitted class (or interface). There's no need to specify non-directs subclasses, they are granted with the permission by default (since they are allowed to extend their direct parent).
Specification explicitly tells that only direct subclasses can be provided in the permits
clause, §8.1.6. Permitted Direct Subclasses:
Every permitted direct subclass specified by the permits clause must
be a direct subclass of C
(§8.1.4
), or a compile-time error occurs.
Permitted classes should be necessarily marked with either of these modifiers: sealed
, non-sealed
and final
(the latter modifier for obvious reasons can't be used with interfaces).
If a subclass is final
it can't be extended.
By declaring a permitted subclass (subinterface) as non-sealed
you're loosening the constraints. Such class is allowed to be extended as a regular class (no permits
clause required).
If the subclass is being marked as sealed
then the cycle repeats: it in turn has to have a permite
clause specifying its direct subclasses.
Here's a quote from the JEP 409: Sealed Classes:
A sealed class imposes three constraints on its permitted subclasses:
1. The sealed class and its permitted subclasses must belong to the same module, and, if declared in an unnamed module, to the same
package.
2. Every permitted subclass must directly extend the sealed class.
3. Every permitted subclass must use a modifier to describe how it propagates the sealing initiated by its superclass:
A permitted subclass may be declared final
to prevent its part of the class hierarchy from being extended further. (Record classes
are implicitly declared final
.)
A permitted subclass may be declared sealed
to allow its part of the hierarchy to be extended further than envisaged by its sealed
superclass, but in a restricted fashion.
A permitted subclass may be declared non-sealed
so that its part of the hierarchy reverts to being open for extension by unknown
subclasses. A sealed
class cannot prevent its permitted subclasses
from doing this.
That said, if you change the declaration of the sealed super interface I1
by specifying non-direct subclasses E
and F
after permits
clause it would not compile:
public sealed interface I1
permits I2, C, D, E, F {
/*...*/
}
And we restore the initial declaration of I1
(by removing E
and F
) the following code would work fine
public static String foo(I1 i1) {
return switch (i1) {
case C c -> "1";
case D d -> "2";
case E e -> "3";
case F f -> "4";
default -> "5";
};
}
main()
public static void main(String[] args) {
System.out.println(foo(new E()));
System.out.println(foo(new F()));
}
Output:
3
4