如果我没有读错JLS§8.1.6§9.1.4,那么密封类/接口允许的类只有direct个子类/接口.

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

public sealed interface I1 permits I2, C, D { /*...*/ }
public final class C implements I1 { /*...*/ }
public final class D implements I1 { /*...*/ }

public sealed interface I2 extends I1 permits E, F { /*...*/ }
public final class E implements I2 { /*...*/ }
public final class F implements I2 { /*...*/ }

如果我正确理解了规范,I1显然允许CD,但不允许EF(通过从I1I2extends层次 struct ).这样对吗?

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

I1 i1 = // ...
return switch (i1) {
    case C c -> "1";
    case D d -> "2";
    case E e -> "3"; // Can we match over E?
    case F f -> "4"; // Can we match over F?
    default  -> "5";
};

推荐答案

I1显然允许CD,但不允许EF.这样对吗?

更准确地说,您可以说CDI1permitted direct subclasses的集合中,这是在第9.1.4节中定义的术语.然而,JLS并没有真正定义"I1permitsCD"是什么意思.

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

14.11.1

如果p适用于类型T(14.30.3),则图案 case 元素p与Tswitch 兼容.

14.30.3:

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

  • 如果T向下转换为U(5.5),则声明引用类型U的模式变量的类型模式适用于另一引用类型T.

显然,E是向下转换的,通过扩大引用转换可以转换为I1,因为E实现了I1.请注意,这一事实与permits无关.这只是E implements I2I2 extends I1的结果.你肯定会同意implementsextends是可传递的!

其次,Switch表达式需要是详尽的.您的Switch表达式总是穷尽的,因为它有一个default大小写.然而,即使没有default个 case ,它仍然是详尽的.

从现在开始,我们将考虑您的switch 表达式,但不考虑default的情况,因为这是permits起作用的地方.在14.11.1.1中指定了确定您编写的 case 标签集是否详尽的规则.你的 case 中重要的一点是(这是一种归纳定义):

  • 对于类型T,如果一组case元素包含一个在类型T(14.30.3)处无条件的模式,则它是穷举的.
  • 对于包含名为C的抽象密封类或接口的类型T,一组case元素是穷举的,如果它是穷举的 对于每个适用的允许直接亚型T.

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

我们首先使用第二个规则--允许的I1的直接子类型是I2CD.因为我们在case元素中有C cD d,所以我们知道我们的case元素集合对于CD(第一条规则)是详尽的.I2也是穷尽的吗?为了确定这一点,我们再次使用第二条规则.I2允许的直接子类型为EF.使用第一个规则,我们知道 case 元素E eF f分别对于EF是穷举的.我们现在已经证明,对于I2CD,CASE元素集是穷举的,因此根据第二条规则,它对于I1是穷举的.

因此,如果你在谈论switch 模式是如何工作的,我认为"感应"是一个更好的词来描述如何验证switch shell 标签的详尽程度.

Java相关问答推荐

如果它最终将被转换为int类型,为什么我们在Java中需要较小的integer类型?

在FML中删除关键帧动画

基于仅存在于父级中的字段查询子文档?

如何使用CSS为选定但未聚焦的表格行设置背景 colored颜色 ?

多个Java线程和TreeMap.put()的非预期行为

根据对象和值的参数将映射<;T、值&>转换为列表<;T&>

使用传递的参数构造异常的Mockito-doThrow(或thenThrow)

这是什么Java构造`(InputStream Is)->;()->;{}`

在AVL树的Remove方法中使用NoSuchElementException时遇到问题

测试期间未执行开放重写方法

把一条整型短裤和两条短裤装成一条长的

在Eclipse中调试未导出的JDK模块的Java包

如果按钮符合某些期望,如何修改它的文本?

JavaFX:为什么我的ComboBox添加了一个不必要的单元格的一部分?

Bash数组的单引号元素并使用空格连接

HBox内部的左对齐按钮(如果重要的话,在页码内)

获取月份';s在java中非UTC时区的开始时间和结束时间

如何在更改分辨率时将鼠标坐标计算为世界坐标

Cucumber中第二个网页的类对象未初始化

如何在Java上为循环数组从synchronized迁移到ReentrantLock