为什么可以将整数文本分配给短类型变量,而不能分配给短类型方法参数?

2022-09-03 02:37:58

为什么我可以这样做:

short a = 5;

但不是这个:

void setNum(short a);

setNum(5);

它抛出:

从 int 到 short 的可能有损转换

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


答案 1

为了理解为什么赋值类型转换在调用被拒绝时工作,必须参考 Java 语言规范主题来了解缩小基元转换的范围和该转换的上下文:赋值上下文调用上下文

根据 JLS,在赋值上下文中允许窄基元转换,如果:

如果变量的类型为 byte、short 或 char,并且常量表达式的值可在变量的类型中表示,则可以使用窄基元转换。

...当分配给 时,它与 常量匹配您的大小写。int5short a

在调用上下文中不允许这种缩小的基元转换,这就解释了为什么在传递常量时调用失败。setNum(short)int5

但是,如果编译器知道我正在传递一个短的可以容纳的常量(如在赋值中),为什么它不允许它编译呢?我的意思是,它们之间有什么区别?

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

应该相当清楚的是,当允许表达式时,bug会更容易蔓延到无法在不损失精度的情况下完成狭窄的地方,因此JLS和编译器在所有情况下都不允许它。

数字上下文中也是如此,因此声明:

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

...同样也是不允许的,尽管它清楚地由正确缩小的常量组成。


答案 2

键入 时,这将自动成为整数。我不确定您正在使用的IDE给您带来了错误,但是它警告您的原因是因为您正在将较大的存储容量值转换为较小的存储容量值,尽管在您的情况下不是,但可能导致您丢失数据。这称为缩小转换5

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

您发布的代码将不起作用,因为当您定义短代码时,如下所示:

short a = 5;

您直接创建一个空头,并且该数字足够小,空头可以容纳它。当您单独键入“5”作为方法参数时,它将作为整数处理,并且JVM不知道它很小并且可以安全地进行短整。要使“5”适合作为该方法的参数,您需要使用缩小转换将其转换为短整,如下所示:

setNum((short) 5);

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

(以下是一些关于此内容的 Oracle 文档)