moh*_*med 34 java casting type-conversion implicit-conversion narrowing
我知道在 Java 中整数文字默认是int,所以如果我写这样的东西
byte byteValue = 2;
Run Code Online (Sandbox Code Playgroud)
Java 自动将文字值2(默认为 int)转换为字节。如果我写同样的事情
byte byteValue = 4/2;
Run Code Online (Sandbox Code Playgroud)
RHS 被评估为一个 int 并隐式转换为一个字节。
但是为什么在以下两种情况下不会发生隐式转换?
int n1 = 4;
byte value = n1/2;
Run Code Online (Sandbox Code Playgroud)
或在此
byte n1 = 4;
byte value = n1/2;
Run Code Online (Sandbox Code Playgroud)
我知道这两个示例的 RHS 都被评估为int。但是为什么Java不像前两种情况那样将其隐式转换为字节。是否只有在存在文字时才会隐式转换为较小的数据类型?
Zab*_*uza 30
让我们看一下您的代码和一些修改后的示例:
// 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;
Run Code Online (Sandbox Code Playgroud)
您将收到示例 3、示例 4和示例 5 中提到的编译时错误。
首先,示例 1 到 4 的简单数学运算是在编译时执行的。因此 Java 将500 / 2在编译时进行计算并将代码替换为 basic byte byteValue = 250;。
Java 中字节的有效值为-128to 127。因此,该范围之外的任何值都不能仅被视为 a,byte而是需要显式转换。因此,示例 1和示例 2通过。
要了解其余部分失败的原因,我们必须学习 Java 语言规范 (JLS),更具体地说是第5.1.3章。缩小原始转换和5.2。分配上下文。
它说从intto的转换byte(如果它在 的范围之外byte)是一个缩小的原始转换并且它可能会丢失信息(出于明显的原因)。它继续解释转换是如何完成的:
有符号整数到整数类型 T 的缩窄转换只会丢弃除 n 个最低位以外的所有位,其中 n 是用于表示类型 T 的位数。此外可能会丢失有关数值大小的信息,这可能会导致结果值的符号与输入值的符号不同。
从第二章开始,如果值为常量表达式,则允许使用窄转换赋值。
此外,如果表达式是类型为
byte、short、char 或 int的常量表达式(第 15.29 节):如果变量的类型为
byte、short 或 char,并且常量表达式的值可在变量的类型中表示,则可以使用缩小原语转换。
长话短说,可能会丢失信息(因为值超出范围)的缩小转换必须明确地通知 Java。Java 不会在没有您强迫的情况下为您完成。这是由演员阵容完成的。
所以例如
byte byteValue = (byte) (500 / 2);
Run Code Online (Sandbox Code Playgroud)
产生的值-6。
你的最后一个例子很有趣:
int n1 = 4;
byte byteValue = n1/2;
Run Code Online (Sandbox Code Playgroud)
虽然这并没有超出范围,但Java仍然将其视为有损缩小转换。为什么会这样?
好吧,Java 不能确保 100%n1在n1/2执行前的最后一秒没有改变。因此,它必须考虑您的所有代码,以查看是否有人n1偷偷摸摸地访问并更改了它。Java 在编译时不做这种分析。
因此,如果您可以告诉 Javan1保持不变4并且实际上永远不会改变,那么这实际上会编译。在这种特定情况下,就足够了final。所以与
final int n1 = 4;
byte byteValue = n1/2;
Run Code Online (Sandbox Code Playgroud)
它实际上会编译,因为 Java 知道它会n1保持不变4并且不能再改变。因此,它可以n1/2在编译时计算2并用byte byteValue = 2;在范围内的basic 替换代码。
所以你做n1 / 2了一个常量表达式,就像之前在5.2 中解释的那样。分配上下文。
您可以在15.29 中查看常量表达式所需的详细信息。常量表达式。基本上所有简单的东西都可以很容易地就地计算,而无需任何方法调用或其他花哨的东西。
从文档:
此外,如果表达式是byte、short、char 或 int 类型的常量表达式(第 15.28 节):
如果变量的类型是 byte、short 或 char,并且常量 表达式的值可以在变量的类型中表示,则可以使用缩小原语转换。
因此,对于前两种情况,值是常量,为什么它的值可以表示为变量 type byte。
byte byteValue = 2;
byte byteValue = 4/2;
Run Code Online (Sandbox Code Playgroud)
而对于后面的两种情况 for n1,这里n1/2不是 a constant expression,所以转换不可用。所以值n1/2不能用变量的类型来表示byte。
int n1 = 4;
byte value = n1/2;
byte n1 = 4;
byte value = n1/2;
Run Code Online (Sandbox Code Playgroud)
https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.2中对此进行了描述
\n\n\n另外,如果表达式是 byte、short、char 或 int 类型的常量表达式 (\xc2\xa715.28):
\n\n
\n- 如果变量的类型是 byte、short 或 char,并且常量表达式的值可以用变量的类型表示,则可以使用缩小基元转换。
\n
结果太大:
\nbyte byteValue = 100000000/2;\n\nerror: incompatible types: possible lossy conversion from int to byte\nRun Code Online (Sandbox Code Playgroud)\n最终变量作为操作数:
\nfinal byte n1 = 4;\nbyte value = n1/2;\nRun Code Online (Sandbox Code Playgroud)\n