为什么我可以将整数文字分配给短类型变量而不是短类型方法参数?

Why can I assign an integer literal to a short type variable but not to a short type method parameter?

为什么我可以这样做:

short a = 5;

但不是这个:

void setNum(short a);

setNum(5);

它抛出:

Possible lossy conversion from int to short

我知道 5 是一个整数文字,您必须对其进行转换。我也明白,如果该值不是常量,那么很明显它需要抛出该错误,因为该值可能达到短类型的限制。但是,如果编译器知道我正在传递一个 short 可以容纳的常量(如在赋值中),为什么它不让它编译呢?我的意思是,它们之间有什么区别?

当您键入 5 时,它会自动成为一个整数。我不确定您使用的 IDE 是什么给了您错误,但它警告您的原因是因为您正在将较大的存储容量值转换为较小的存储容量值,虽然不是您的情况,但可以导致你丢失数据。这称为 缩小转换

整数可以容纳32位数据,而短整数只能容纳16位数据。因此,例如(实际上数字会大得多),一个 int 的值等于 50,然后您将其转换为 short,数据将被剪切为“5”,因为 short 没有足够大的内存分配。

您发布的代码将无法正常工作,因为当您按如下方式定义 short 时:

short a = 5;

你是直接做一个空头,数量足够小,空头可以容纳它。当您单独键入“5”作为方法参数时,它会作为一个整数处理,而 JVM 并不知道做一个短的它既小又安全。为了使“5”适合作为该方法的参数,您需要使用缩小转换将其转换为 short,如下所示:

setNum((short) 5);

但如前所述,如果您实际上不知道 int 的值,并且您不确定它是否足够小以转换为 short,这可能会在您的代码中产生错误,因为一些数字会被砍掉。

Here 是关于此的一些 Oracle 文档)

为了理解为什么赋值类型转换有效而调用被拒绝,必须参考 Java 语言规范主题 narrowing primitive conversions and the context of that conversion: assignment context and invocation context

根据 JLS,在 赋值上下文 中允许缩小原语转换,如果:

A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.

... 当分配给 short a.

时,它与 int 常量 5 相匹配

调用上下文 中不允许这样的缩小原始转换,这解释了为什么在传递 int 常量时您对 setNum(short) 的调用失败 5.

But why if the compiler knows I'm passing a constant that a short can hold (as in the assignment) it doesn't let it compile? I mean, what is the difference between them?

JLS 一定不想给编译器增加这种额外逻辑的负担。在调用情况下,与形式参数类型匹配的参数是一个表达式——编译器已经确定了类型,但不需要检查表达式的值是否也可以安全地缩小。在这种情况下,作为一个常量,us 很清楚它可以,但是在执行上下文中允许编译器不理会该检查,并且实际上是正确的禁止它。

应该很清楚,当允许使用表达式时,错误会更容易潜入无法在不损失精度的情况下进行缩小的地方,因此 JLS 和编译器在所有情况下都不允许使用它。

numeric context中也是如此,所以声明:

short a = 5;short b = a * 5;

... 同样是不允许的,尽管它显然由正确缩小的常量组成。