Java Sealed 类/接口的许可关系是否具有传递性

tww*_*wwt 6 java sealed sealed-class java-17

如果我正确地阅读了 JLS \xc2\xa78.1.6\xc2\xa79.1.4,则密封类/接口允许的类只是直接子类/接口。

\n

为了说明这一点,请考虑以下示例:

\n
public sealed interface I1 permits I2, C, D { /*...*/ }\npublic final class C implements I1 { /*...*/ }\npublic final class D implements I1 { /*...*/ }\n\npublic sealed interface I2 extends I1 permits E, F { /*...*/ }\npublic final class E implements I2 { /*...*/ }\npublic final class F implements I2 { /*...*/ }\n
Run Code Online (Sandbox Code Playgroud)\n

如果我正确理解了规范,I1显然允许CandD但不允许Eand F(通过fromextends的层次结构)。它是否正确?I2I1

\n

我问的原因是以下类型的 switch 表达式允许使用哪些模式:

\n
I1 i1 = // ...\nreturn switch (i1) {\n    case C c -> "1";\n    case D d -> "2";\n    case E e -> "3"; // Can we match over E?\n    case F f -> "4"; // Can we match over F?\n    default  -> "5";\n};\n
Run Code Online (Sandbox Code Playgroud)\n

Swe*_*per 3

I1显然允许C且 ,D但不允许EF。它是否正确?

更准确地说,您可以说C位于 的允许的直接子类集合D中,这是第 9.1.4 节中定义的术语。JLS 并没有真正定义“允许和”的含义。I1I1 CD

至于你的 switch 表达式,它起作用的原因有两个。首先,如果开关选择器表达式的类型可向下转换为该类型,则可以在开关标签中编写类型模式。

14.11.1

如果 p 适用于类型 T(14.30.3),则模式 case 元素 p 与 T 兼容。

14.30.3:

如果以下规则之一适用,则称模式 p 适用于类型 T:

显然,可以通过扩大引用转换E进行向下转换,因为实现了. 请注意,这个事实与 无关。它只是和的结果。你肯定会同意这一点并且是传递性的!I1EI1permitsE implements I2I2 extends I1implementsextends

其次,switch 表达式需要详尽无遗。你的 switch 表达式总是详尽的,因为它有一个default案例。然而,即使没有案例,它仍然是详尽的default

从现在开始,我们将考虑您的 switch 表达式,但不考虑大小写default,因为这才是permits发挥作用的地方。确定您编写的案例标签集是否详尽的规则在14.11.1.1中指定。您的案例的重要部分是(这是一种归纳定义):

  • 如果一组 case 元素包含在类型 T 上无条件的模式,那么它对于类型 T 来说是详尽的(14.30.3)。
  • 如果一组 case 元素对于 T 的每个适用的允许的直接子类型都是穷举的,则对于包含名为 C 的抽象密封类或接口的类型 T 来说,它是穷举的。

在您的情况下,“适用的允许的 T 的直接子类型”实际上与“允许的 T 的直接子类型”相同。您还可以将“包含抽象且密封的类或名为 C 的接口的类型 T”视为相同T- “包含”关系与您的情况无关。记住T=I1了,我们就可以开始“运行”这个算法了。

我们首先使用第二条规则 - 允许的直接子类型I1I2,CD。因为我们在 case 元素中有一个C cand ,所以我们知道我们的 case 元素集对于and (第一条规则)是详尽的。它也详尽无遗吗?为了确定这一点,我们再次使用第二条规则。允许的直接子类型是和。使用第一条规则,我们知道 case 元素和分别对于和是详尽的。我们现在已经证明,根据第二条规则,案例元素集对于 和 是详尽的,因此对于 也是详尽的。D dCDI2I2EFE eF fEFI2CDI1

因此,如果您正在谈论开关模式的工作原理,我认为“归纳”是一个更好的词来描述如何验证开关盒标签的详尽性。