解释
让我们看一下您的代码和一些修改后的示例:
// Example 1
byte byteValue = 2;
// Example 2
byte byteValue = 4/2;
// Example 3
byte byteValue = 2000;
// Example 4
byte byteValue = 500/2;
// Example 5
int n1 = 4;
byte byteValue = n1/2;
无损转换
您将收到示例 3、示例 4和示例 5的上述编译时错误。
首先,示例 1 到 4 的简单数学运算是在编译时执行的。因此 Java 将500 / 2
在编译时计算并将代码替换为基本byte byteValue = 250;
.
Java 中字节的有效值为-128
to 127
。因此,任何超出该范围的值都不能仅仅被视为 a byte
,而是需要显式转换。因此,示例 1和示例 2通过。
有损缩小转换
要理解为什么其余的都失败了,我们必须研究 Java 语言规范(JLS),更具体地说是第5.1.3 章。缩小原始转换和5.2。分配上下文。
它说从int
to的转换byte
(如果它超出 的范围byte
)是一种缩小的原始转换,它可能会丢失信息(出于明显的原因)。它继续解释转换是如何完成的:
有符号整数到整数类型 T 的窄化转换只会丢弃除 n 个最低位之外的所有位,其中 n 是用于表示类型 T 的位数。此外,可能会丢失有关数值大小的信息,这可能会导致结果值的符号与输入值的符号不同。
从第二章开始,如果值是常量表达式,则允许进行窄转换的赋值。
此外,如果表达式是类型byte
、short、char 或 int 的常量表达式(第 15.29 节):
byte
如果变量的类型是、short 或 char ,并且常量表达式的值可以用变量的类型表示,则可以使用缩小原语转换。
长话短说,可能会丢失信息(因为值超出范围)的缩小转换必须明确地向 Java 宣布。Java 不会在您不强制的情况下为您完成它。这是由演员完成的。
所以例如
byte byteValue = (byte) (500 / 2);
产生的价值-6
。
常量表达式
你的最后一个例子很有趣:
int n1 = 4;
byte byteValue = n1/2;
虽然这没有超出范围,但 Java 仍然将其视为有损缩小转换。为什么会这样?
好吧,Java 不能保证 100%在执行n1
前的最后一秒没有改变n1/2
。因此,它必须考虑您的所有代码,以查看是否有人n1
偷偷访问并更改它。Java 不会在编译时进行这种分析。
因此,如果您可以告诉 Javan1
保持不变4
并且实际上永远不会改变,那么它实际上会编译。在这种特定情况下,它就足够了final
。所以随着
final int n1 = 4;
byte byteValue = n1/2;
它实际上会编译,因为 Java 知道它会n1
保留4
并且不能再更改。因此,它可以n1/2
在编译时计算2
并用 basic 替换代码byte byteValue = 2;
,这在范围内。
所以你做n1 / 2
了一个常量表达式,就像之前在5.2 中解释的那样。分配上下文。
您可以查看15.29 中需要有一个常量表达式的详细信息。常量表达式。基本上所有简单的东西都可以很容易地计算出来,而无需任何方法调用或其他花哨的东西。