【问题标题】:Why doesn't compound assignment in Java catch overflow problems?为什么 Java 中的复合赋值不能捕获溢出问题?
【发布时间】:2011-07-25 18:01:00
【问题描述】:

令我震惊的是,以下代码甚至可以在没有警告的情况下编译:

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 节)有这样的说法:

E1 op = E2 形式的复合赋值表达式等价于 E1 = (T) ((E1) op (E2)),其中 T 是 E1 的类型,除了对 E1 求值 只有一次。

这对我来说似乎很荒谬。为什么他们觉得有必要在这里明确投射?似乎自动类型转换无论如何都会处理扩大,并且像这样自动缩小几乎肯定会导致整数溢出。

【问题讨论】:

  • 好问题。对我来说从来没有多大意义。也许 James Gosling 会回应,因为他现在是 Google 员工,应该有很多空闲时间......
  • @squawknull - 是什么让您认为 Google 员工会在毫无意义的 SO 辩论上浪费他宝贵的“每周一天”? :-)
  • @Stephen C:这就是我今天的笑点。

标签: java integer-overflow compound-assignment


【解决方案1】:

Here 是一种解释:

当您进行赋值时(第一个代码 sn-p),java 会强制执行类型检查,因为 LHS 和 RHS 很可能彼此独立。

但是复合运算符更像 增量运算符。 += 修改变量的值 参与,而不是分配一个新的 变量的值。当你修改 一个字节,你期望一个字节作为 结果。为了让生活更轻松,java 确实 隐式类型转换 复合运算符,因为它们是 修饰符。

【讨论】:

    【解决方案2】:

    此链接已分析您提出的问题。

    Varying behavior for possible loss of precision

    为避免令人不快的意外,请勿 使用复合赋值运算符 byte、short 或 字符。使用复合赋值时 int 类型变量的运算符, 确保上的表达式 右手边不是长型的, 浮动,或双。使用化合物时 变量的赋值运算符 输入浮点数,确保表达式 右侧不是类型 双倍的。这些规则足以 防止编译器生成 危险的变窄管型。

    【讨论】:

      【解决方案3】:

      复合赋值运算符由 JLS (15.26.2) 指定如下:

      E1 op= E2 形式的复合赋值表达式等价于

            E1 = (T)((E1) op (E2))`, 
      

      其中 T 是 E1 的类型,除了 E1 只计算一次。"

      在这种情况下,E1 的类型为 int E2 的类型为 long,而 op 的类型为 +。所以这相当于:

      value = (int)(value + increment);
      

      intlong 的相加得到 long,然后在分配之前将其转换回 int。这一切都很好,因此没有编译错误。

      这与简单赋值(即value = value + increment;)的区别在于简单赋值没有类型转换。


      好的,那么为什么他们会这样定义?

      我认为原因是为了让这样的例子起作用:

          byte b = ...
          b += 1;
      

      如果没有类型转换,b += 1 将是编译错误,您需要将其编写为:

          b += (byte) 1;
      

      【讨论】:

      • 你不认为即使是字节也允许它是危险的吗?如果该代码不是加 1,而是加 128,该怎么办?
      猜你喜欢
      • 2011-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-12
      • 2013-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多