无法编译:
void test(Integer x) {
switch (x) {
case 'a':
}
}
编译OK:
void test(Byte x) {
switch(x) {
case 'a':
}
}
'a'
情况下的代码将在x
为byte 的情况下执行97
。(如果您不相信我,请尝试。)有关真正的解释,请参阅我的答案。
无法编译:
void test(Integer x) {
switch (x) {
case 'a':
}
}
编译OK:
void test(Byte x) {
switch(x) {
case 'a':
}
}
'a'
情况下的代码将在x
为byte 的情况下执行97
。(如果您不相信我,请尝试。)有关真正的解释,请参阅我的答案。
Answers:
原因很复杂,但是原因全在Java语言规范的细节中(如果需要,可以打印精美)。
首先,JLS 14.11说了以下about switch
语句:
“与switch语句相关联的每种情况常量都必须与switch语句的Expression(第5.2节)的类型兼容。”
这意味着'a'
需要 分别分配给Integer
和Byte
。
但这听起来不对:
您会认为,因为'a'
应该可以将 since 分配给一个,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节)
- 拆箱转换,然后进行扩大的原始转换。”
从去'a'
到Integer
,我们需要1扩大char
价值的int
,然后框int
到Integer
。但是,如果您查看允许的转换组合,则无法进行加宽原始转换和装箱转换。
因此'a'
到Integer
是不允许的。这解释了第一种情况下的编译错误。
您会认为'a'
to Byte
是不被允许的,因为这将涉及原始的缩小转换...根本不在列表中。实际上,文字是一种特殊情况。 JLS 5.2继续说以下内容。
“此外,如果该表达式是类型为byte,short,char或int 的常量表达式(第15.28节):
如果变量的类型为byte,short或char,并且常量表达式的值可以表示为变量的类型,则可以使用缩窄的原始转换。
如果变量的类型为
Byte
,Short
或Character
,并且常量表达式的值分别以字节,short或char类型表示,则可以使用紧缩原始转换和装箱转换。
其中的第二个适用'a'
于Byte
,因为:
'a'
是97
十进制,在byte
(-128
至+127
)的范围内。这解释了为什么第二个示例中没有编译错误。
1-我们不能'a'
将a 装箱Character
,然后再扩大Character
到,Integer
因为Character
这不是Java的Java子类型Integer
。如果源类型是目标类型的子类型,则只能使用加宽引用转换。
int
用作开关类型吗?(因为char -> int
允许原始加宽)