查询 1:
byte a = 0; // int to byte implicit conversion happens, correct!, no CTE [compile time error]
setByte(0); // CTE!, why ? implicit conversion do not happen here
void setByte(byte b){}
查询 2:
byte b_byte = 128 - 1; // integer literal computation results to 127 int which implicitly casts to byte and as 127 is in range of byte so no CTE, Correct!
int a_int = 2147483647; // in range of int, so no CTE
int b_int = 2147483648 - 1; // still in range of int but CTE, why ?
请解释一下,并指出定义这些规则的 JLS 部分。
首先,赋值转换,JLS 5.2 涵盖了可以分配的值。
此外,如果表达式是类型为
byte
、short
、char
或int
的常量表达式 (§15.28(:
- 如果变量的类型为
byte
、short
或char
,并且常量表达式的值可以用变量的类型表示,则可以使用窄基元转换。
对于byte a = 0;
常量表达式是缩小到byte
的int
0
。
接下来,调用上下文,JLS 5.3 介绍了哪些值可以传递给方法。
严格和松散的调用上下文都不包括赋值上下文中允许的整数常量表达式的隐式缩小。
因此,您的代码对于常量表达式缩小转换有一个编译器错误,该错误在调用上下文(方法调用(中是不允许的。
setByte(0); // no implicit narrowing conversion, even if it's a constant expression
void setByte(byte b){}
您的代码128 - 1
是一个常量表达式,缩小到byte
。
但是,不允许2147483648 - 1
2147483648
因为它本身不是有效的int
文字,第 3.10.1 节 "整数文字"。
如果十进制文本2147483648出现在一元减运算符的操作数以外的任何位置,或者如果 int 类型的十进制文本大于 2147483648 (231(,则存在编译时错误。
如果真的想用一个不必要的复杂表达式来初始化一个int
,你可以使用long
文字来使表达式合法化:
2147483648L - 1
但是你必须显式地将表达式转换为int
;没有从比int
宽到int
的隐式缩小
(int) (2147483648L - 1)
奇怪的是,您不必在表达式周围放置括号,以便强制转换应用于整个表达式,尽管为了清楚起见,我强烈建议使用括号。
(int) 2147483648L - 1 // It's 2147483647!
long
文本上强制转换int
超出int
范围,将生成 -2147483648,即有效的int
值。 在这里减去 1 涉及负方向的溢出,产生预期的2147483647值。