无法编译:
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允许原始加宽)