通过 Number 和开关选择器表达式的自定义类型违反 JLS

JLS violations via Number and custom types for switch selector expression

JLS 17 提及 switch 选择器表达式(就像它之前的 JLS')

The type of the selector expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (§8.9), or a compile-time error occurs.

然而,这可以编译(并且有效)

public class rough2 {
    class f{
        public static void sop(Object o){System.out.println(o);}
    }
    public static void main(String[] args) {
        Number no = 10.23f;
        switch (no) {
            case Integer i -> f.sop("%d is integer".formatted(i));
            case Float fl -> f.sop("%3.2f is float".formatted(fl));
            default -> f.sop("don't know about "+no);
        }
    }
}

现在,Number 不是列出的类型之一。

  1. 为什么没有编译错误?

有趣的是,no.getClass() 给出 java.lang.Float。通用自动装箱是一回事吗?

更奇怪的是(也许这应该是一个单独的问题 - 如果是的话请告诉我),将上面的主要方法替换为下面的方法仍然有效。

public static void main(String[] args) {
        class a {}
        class b extends a {}
        a obj = new a();//new b();
        switch (obj) {
            case b typeB -> f.sop("is sub type b");
            case a typeA -> f.sop("is a");
        }
    }
  1. 怎么不违反 JLS?

请注意,您可能需要 --enable-preview JDK 17 至 运行 上述代码中的功能。

您显示的具体语法定义在JEP 406: Pattern Matching for switch (Preview), and is a preview feature. Preview features are not defined in the JLS itself, but instead are defined separately, as mentioned in JSL 17 section 1.5. Preview Features:

Preview language features are specified in standalone documents that indicate changes ("diffs") to The Java® Language Specification for that release. The specifications of preview language features are incorporated into The Java® Language Specification by reference, and made a part thereof, if and only if preview features are enabled at compile time.

Java SE 17 defines one preview language feature: Pattern Matching for switch. The standalone document which specifies this preview feature is available at the Oracle web site which hosts The Java® Language Specification: https://docs.oracle.com/javase/specs/.

用于预览功能的 JLS 17 的 'diff' 文档是 Pattern Matching for switch。当您指定 --enable-preview 时,它 'applies'。其中,它删除了您在问题中引用的行:

The type of the selector expression must be char, byte, short, int, Character, Byte, Short, Integer, String, or an enum type (8.9), or a compile-time error occurs.

关于您的问题“为什么没有编译错误?”,因为这就是此功能的工作原理。您提供一个 Number,然后检查它是 Integer 还是 Float,或者应用默认值,IntegerFloat 都是Number。我建议阅读 JEP 406 了解更多详情。

至于“泛型自动装箱是一回事吗?”,这里不涉及泛型。您将 float 文字分配给对象类型的变量,因此它被自动装箱为 Float,并且给定 NumberFloat 的超类,分配是有效的。

我不确定你所说的“更奇怪”部分是什么意思,或者你认为它奇怪的原因,但再次:阅读 JEP 406 了解更多详情。