为什么编译器不为这个加法操作提供一个错误?
这个问题在这里已经有了答案:
答案由JLS 15.26.2提供:
例如,以下代码是正确的:
short x = 3;
x += 4.6;
并导致x的值为7,因为它相当于:
short x = 3;
x = (short)(x + 4.6);
所以,正如你所看到的,最新的情况实际上是有效的,因为添加赋值(和任何其他操作符赋值一样)对左手类型执行隐式转换(在你的情况中a
是一个byte
)。 扩展,它相当于byte e = (byte)(a + b);
,它会愉快地编译。
反编译你的代码将解释Java正在做什么,它的原因通常可以在语言规范中找到。 但在我们进入之前,我们必须确定几个重要的概念:
一个字面数字总是用int
。
如果后缀为ASCII字母L或l(ell),则整数常量的类型为long; 否则它是int类型的(§4.2.1)。
一个byte
只能包含-128和127之间的整数值。
尝试分配大于可容纳它的类型的文字将导致编译错误。 这是你遇到的第一个场景。
所以我们回到这种情况:为什么添加两个字节明显比字节可以处理的字节更多而不会产生编译错误?
它不会因溢出而引发运行时异常。
这是两个数字加在一起突然产生一个非常小的数字的情况。 由于byte
范围较小,所以很容易溢出; 例如,加1到127就可以了,结果是-128。
它将要包装的主要原因是Java处理原始值转换的方式; 在这种情况下,我们正在谈论缩小转换。 也就是说,即使生成的总和大于byte
,缩小转换将导致丢弃信息以允许数据适合byte
,因为此转换永远不会导致运行时异常。
逐步打破您的方案:
a = 127
和b = 5
加起来产生132。 a
和b
是byte
类型,所以结果也必须是byte
类型。 (byte)(a += b)
。 a
和z
都包含结果-124。 我得出的结论是,涉及变量的表达式的结果不能得到保证。 结果值可能在字节范围之内或之外,因此编译器会抛出错误。
不,这不是原因。 静态类型语言的编译器以这种方式工作:任何变量都必须声明和输入,所以即使它的值在编译时不知道,它的类型也是已知的。 隐式常量也是如此。 基于这个事实,计算尺度的规则基本上是这样的:
(这些实际上是一个简化的视图;实际上可能会更复杂一点)。
将其应用于您的案例:
byte d = 1 + b
实际的比例是:
byte = int + byte
...(因为1
被认为是一个隐式的int
常量)。 因此,应用第一条规则,变量必须至少具有int
尺度。
在这种情况下:
byte z = (a+=b);
实际的比例是:
byte = byte += byte
......这是可以的。
更新
那么,为什么byte e = a + b
产生编译时错误?
正如我所说的,java中的实际类型规则更为复杂:尽管一般规则适用于所有类型,但基元byte
和short
类型受到更多限制:编译器假定添加/减去两个或更多字节/短路可能导致原因一个溢出(如@Makoto所述),所以它需要被存储为下一个被认为“更安全”的比例类型: int
。
上一篇: Why does the compiler not give an error for this addition operation?