为什么在 Java 切换整数包装器时,“char”情况是否无法编译,但是当切换超过 Byte 时编译是可以的?
不编译:
void test(Integer x) {
switch (x) {
case 'a':
}
}
编译正常:
void test(Byte x) {
switch(x) {
case 'a':
}
}
不编译:
void test(Integer x) {
switch (x) {
case 'a':
}
}
编译正常:
void test(Byte x) {
switch(x) {
case 'a':
}
}
原因相当复杂,但它们都在Java语言规范的细节中(如果你愿意的话,可以写细则)。
首先,JLS 14.11对语句进行了如下说明:switch
“与 switch 语句关联的每个事例常量都必须赋值与 switch 语句的表达式类型兼容 (§5.2)。”
这意味着需要分别分配给 和 。'a'
Integer
Byte
但这听起来不对:
您可能会认为,因为应该可以分配给一个因为->赋值是合法的。(任何值都适合 .)'a'
Integer
char
int
char
int
您可能会认为,因为不应该分配给一个因为->分配是不合法的。(大多数值不适合字节。'a'
Byte
char
byte
char
事实上,这些都不正确。为了理解为什么,我们需要阅读JLS 5.2实际上关于赋值上下文中允许的内容。
“工作分配上下文允许使用下列方法之一:
- 身份转换 (§5.1.1)
- 加宽基元转换 (§5.1.2)
- 加宽参考转换 (§5.1.5)
- 加宽参考转换,然后进行拆箱转换
- 加宽参考转换,然后进行取消装箱转换,然后进行加宽基元转换
- 拳击转换 (§5.1.7)
- 装箱转换后进行加宽参考转换
- 拆箱转换 (§5.1.8)
- 拆箱转换,然后加宽基元转换。
要从 到 ,我们需要将值扩大 1 到 一个 然后 框 到 一个 .但是,如果您查看允许的转换组合,则无法先进行加宽基元转换,然后再进行装箱转换。'a'
Integer
char
int
int
Integer
因此不允许这样做。这解释了第一种情况下的编译错误。'a'
Integer
您可能会认为不允许这样做,因为这将涉及原始的缩小转换...这根本不在列表中。实际上,文字是一种特例。JLS 5.2继续说了以下内容。'a'
Byte
“此外,如果表达式是字节、短、字符或 int 类型的常量表达式 (§15.28):
如果变量的类型为 byte、short 或 char,并且常量表达式的值可在变量的类型中表示,则可以使用窄基元转换。
如果变量的类型为 Byte、Short 或
Character
,并且常量表达式的值分别以byte
、short
或 char 类型表示,则可以使用缩小基元转换,然后进行装箱转换。
其中第二个适用于 ,因为:'a'
Byte
'a'
97
byte
-128
+127
这就解释了为什么在第二个示例中没有编译错误。
1 - 我们不能将“a”
框入字符
,然后将字符
扩大到整数
,因为字符
不是整数
的Java子类型。仅当源类型是目标类型的子类型时,才能使用加宽引用转换。