令我震惊的是,事实证明,下面的代码将编译,甚至没有警告:

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类型变量的运算符, 确保表达式 右侧不是类型的, 漂浮,或双重。使用化合物时 变量的分配运算符 类型浮动,确保表达式 在右侧不是类型 双倍的。这些规则足以 防止编译器生成 危险的缩小演员。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top