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