为了理解为什么赋值类型转换在调用被拒绝时工作,必须参考 Java 语言规范主题来了解缩小基元转换的范围和该转换的上下文:赋值上下文和调用上下文。
根据 JLS,在赋值上下文中允许窄基元转换,如果:
如果变量的类型为 byte、short 或 char,并且常量表达式的值可在变量的类型中表示,则可以使用窄基元转换。
...当分配给 时,它与 常量匹配您的大小写。int
5
short a
在调用上下文中不允许这种缩小的基元转换,这就解释了为什么在传递常量时调用失败。setNum(short)
int
5
但是,如果编译器知道我正在传递一个短的可以容纳的常量(如在赋值中),为什么它不允许它编译呢?我的意思是,它们之间有什么区别?
JLS 一定不想用这个额外的逻辑来给编译器带来负担。在调用情况下,类型与形式参数匹配的参数是一个表达式 - 编译器已经必须确定类型,但它不需要检查表达式的值是否可以安全地缩小。在这种情况下,作为一个常量,我们很清楚它可以,但在执行上下文中,编译器可以不打扰该检查,并且实际上不允许它是正确的。
应该相当清楚的是,当允许表达式时,bug会更容易蔓延到无法在不损失精度的情况下完成狭窄的地方,因此JLS和编译器在所有情况下都不允许它。
在数字上下文中也是如此,因此声明:
short a = 5;short b = a * 5;
...同样也是不允许的,尽管它清楚地由正确缩小的常量组成。