JLS 17 mentions for the switch selector expression (like the JLS' before it)
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.
Yet, this compiles (and works)
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);
}
}
}
Now, Number isn't one of the listed types.
- Why is there no compilation error?
Interestingly, no.getClass() gives java.lang.Float. Is generic autoboxing a thing?
Even more bizarrely (and maybe this should be a separate question - if so tell me), replacing the above main method with the one below still works.
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");
}
}
- How is this not a JLS violation?
Please note that you may need to --enable-preview features in JDK 17 to run the above code.
The specific syntax you show is defined in 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:
This 'diff' document of JLS 17 for the preview feature is Pattern Matching for switch. It 'applies' when you specify
--enable-preview. Among others, it removes the line you quote in your question:As to your question "Why is there no compilation error?", because that is how this feature works. You provide a
Number, and then check whether it is anIntegeror aFloat, or otherwise apply a default, bothIntegerandFloatare subclasses ofNumber. I recommend reading JEP 406 for more details.As to "Is generic autoboxing a thing?", there are no generics involved here. You assign a
floatliteral to a variable of an object type, so it is autoboxed toFloat, and givenNumberis a superclass ofFloat, the assignment is valid.I'm not sure what you mean with the "Even more bizarrely" part, or why you think it is bizarre, but again: read JEP 406 for more details.