繁体   English   中英

为什么Java中的复合赋值没有捕获溢出问题?

[英]Why doesn't compound assignment in Java catch overflow problems?

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

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仅被评估一次。

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

是一个解释:

当你执行一个赋值(第一个代码片段)时,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转换为int 这一切都很好,因此没有编译错误。

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


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

我认为原因是做这样的例子:

    byte b = ...
    b += 1;

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

    b += (byte) 1;

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

不同的行为可能会导致精度下降

为避免令人不快的意外,请不要对byte,short或char类型的变量使用复合赋值运算符。 在int类型的变量上使用复合赋值运算符时,请确保右侧的表达式不是long,float或double类型。 在float类型的变量上使用复合赋值运算符时,请确保右侧的表达式不是double类型。 这些规则足以防止编译器生成危险的缩小转换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM