为什么java中的复合赋值不会捕获溢出问题?
-
14-11-2019 - |
题
令我震惊的是,事实证明,下面的代码将编译,甚至没有警告:
public void test()
{
int value = 2000000000;
long increment = 1000000000;
value += increment;
}
而这给出了一个编译时错误,正如您所期望的那样:
public void test()
{
int value = 2000000000;
long increment = 1000000000;
value = value + increment;
}
我查了一下,确实,JLS(第15.26.2节)有这样的说法:
形式E1op=E2的复合赋值表达式相当于 E1=(T)((E1)op(E2)),其中T是E1的类型,除了e1被评估 只有一次。
这对我来说似乎很荒谬。为什么他们觉得有必要明确地投在这里?似乎自动类型转换无论如何都会处理扩展,并且像这样自动缩小几乎可以保证导致整数溢出。
解决方案
此处是一个说明:
执行作业(第一个代码片段)时,Java强制执行类型检查,因为LHS和RHS可能非常彼此独立。
但复合操作员更像 增量操作员。+= 修改变量的值 涉及,而不是分配新的 变量的值。当你修改时 一个字节,你期待一个字节 结果。让生活更轻松,Java 隐式类型转换 复合算子因为它们是 修饰符。
其他提示
复合赋值运算符由JLS指定(15.26.2)如下:
"形式的复合赋值表达式
E1 op= E2
相当于
E1 = (T)((E1) op (E2))`,
其中T是E1的类型,除了E1只计算一次。"
在这种情况下,E1是类型 int
E2是类型 long
, ,而op是 +
.所以这相当于:
value = (int)(value + increment);
添加一个 int
和一个 long
给出了一个 long
然后再转换回一个 int
分配之前。这一切都很好,因此没有编译错误。
这与简单赋值(即 value = value + increment;
),是简单的赋值没有typecast。
好吧,那么 为什么 他们是这样定义的吗?
我认为,原因是做这样的例子工作:
byte b = ...
b += 1;
没有typecast, b += 1
这将是一个编译错误,你需要把它写成:
b += (byte) 1;
此链接已分析您提出的问题。
避免令人不快的惊喜,不要 使用复合分配运营商 类型字节,短,或者的变量 克。使用复合分配时 int类型变量的运算符, 确保表达式 右侧不是类型的, 漂浮,或双重。使用化合物时 变量的分配运算符 类型浮动,确保表达式 在右侧不是类型 双倍的。这些规则足以 防止编译器生成 危险的缩小演员。