为什么编译器不为此添加操作提供错误?

Fly*_*bit 30 java

我知道编译器对整数文字进行隐式类型转换.例如:

byte b = 2; // implicit type conversion, same as byte b = (byte)2;
Run Code Online (Sandbox Code Playgroud)

如果范围溢出,编译器会给出错误:

byte b = 150; // error, it says cannot convert from int to byte
Run Code Online (Sandbox Code Playgroud)

当变量传递表达式时,编译器会给出相同的错误:

byte a = 3;
byte b = 5;
byte c = 2 + 7; // compiles fine
byte d = 1 + b; // error, it says cannot convert from int to byte
byte e = a + b; // error, it says cannot convert from int to byte
Run Code Online (Sandbox Code Playgroud)

我得出的结论是,无法保证涉及变量的表达式的结果.结果值可以在字节范围之内或之外,因此编译器会抛出错误.

令我困惑的是,当我这样说时,编译器不会抛出错误:

byte a = 127;
byte b = 5;
byte z = (a+=b); // no error, why ?
Run Code Online (Sandbox Code Playgroud)

为什么不给我一个错误?

Mak*_*oto 22

虽然反编译你的代码将解释什么 Java正在做,原因为什么它做它通常可以在语言规范中.但在我们进入之前,我们必须建立一些重要的概念:

所以我们回到这种情况:为什么要添加两个明显多于字节可以处理的字节而不会产生编译错误?

由于溢出,它不会引发运行时异常.

这是两个加在一起的数字突然产生一个非常小的数字的情况.由于体积小byte,所以很容易溢出; 例如,添加1到127会这样做,结果为-128.

它将要解决的主要原因是Java处理原始值转换的方式; 在这种情况下,我们谈论的是缩小转换.也就是说,即使产生的总和更大的byte,缩小转换将导致信息被丢弃允许数据以适应一个byte,因为这种转换从来没有导致运行时异常.

要逐步分解您的场景:

  • Java添加a = 127b = 5一起生成132.
  • Java理解它a并且b是类型的byte,因此结果也必须是类型byte.
  • 这个整数结果仍然是132,但此时,Java将执行转换以将结果缩小到一个字节内 - 有效地给你(byte)(a += b).
  • 现在,无论是az包含结果-124由于环绕.


Lit*_*nti 5

我得出的结论是,无法保证涉及变量的表达式的结果.结果值可以在字节范围之内或之外,因此编译器会抛出错误.

不,那不是原因.静态类型语言的编译器以这种方式工作:必须声明和键入任何变量,因此即使在编译时未知其值,其类型也是已知的.隐式常量也是如此.基于这个事实,计算尺度的规则基本上是:

  • 任何变量必须具有与其右侧表达式相同或更高的比例.
  • 任何表达式都与其所涉及的最大术语具有相同的比例.
  • 一个明确的施放力量,即科西嘉,右侧表达的规模.

(这些实际上是一个简化的视图;实际上可能有点复杂).

将它应用于您的案例:

byte d = 1 + b
Run Code Online (Sandbox Code Playgroud)

实际比例是:

byte = int + byte
Run Code Online (Sandbox Code Playgroud)

...(因为1被视为隐式int常量).因此,应用第一个规则,变量必须至少具有int比例.

在这种情况下:

byte z = (a+=b);
Run Code Online (Sandbox Code Playgroud)

实际比例是:

byte = byte += byte
Run Code Online (Sandbox Code Playgroud)

......没关系.

更新

那么,为什么会byte e = a + b产生编译时错误?

正如我所说的,在Java的实际类型规则更复杂的:虽然一般规则适用于所有类型的,原始byteshort类型是更受限制:编译器假定加法/从其减去两个或多个字节/短裤是冒着引起上溢(正如@Makoto所说),因此需要将其存储为被认为"更安全"的下一类型:a int.


Tha*_*ish 5

答案由JLS 15.26.2提供:

例如,以下代码是正确的:

short x = 3;

x += 4.6;

并且结果x的值为7,因为它相当于:

short x = 3;

x = (short)(x + 4.6);

因此,正如您所看到的,最新的情况实际上是有效的,因为添加赋值(与任何其他运算符赋值一样)对左手类型执行隐式强制转换(在您的情况下a为a byte).扩展,相当于byte e = (byte)(a + b);,将编译愉快.