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

发布于 2024-10-27 06:38:42 字数 581 浏览 7 评论 0原文

令我震惊的是,事实证明以下代码将在没有警告的情况下进行编译:

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 进行求值 仅一次。

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

To my shock, it turns out that the following code will compile without even warnings:

public void test()
{
    int value = 2000000000;
    long increment = 1000000000;
    value += increment;
}

Whereas this gives a compile-time error, as you would expect:

public void test()
{
    int value = 2000000000;
    long increment = 1000000000;
    value = value + increment;
}

I checked it up and indeed, the JLS (section 15.26.2) has this to say:

A compound assignment expression of the form E1 op = E2 is equivalent to
E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated
only once.

This seems ridiculous to me. Why did they feel the need to explicitly cast here? It seems that automatic type conversion would have handled the widening anyway, and automatically narrowing like this is pretty much guaranteed to result in integer overflow.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

澜川若宁 2024-11-03 06:38:42

这里是一种解释:

当您进行分配(第一个代码片段)时,java 会强制执行类型检查,因为 LHS 和 RHS 很可能彼此独立。

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

Here is one explanation:

When you do an assignment (the first code snippet), java enforces type checking because the LHS and RHS may very well be independent of each other.

But the compound-operator is more like
an incremental operator. The +=
modifies the value of the variable
involved, rather than assigning a new
value to the variable. When you modify
a byte, you expect a byte as the
result. To make life easier, java does
an implicit type conversion for
compound-operators because they are
modifiers.

離人涙 2024-11-03 06:38:42

复合赋值运算符由 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 ,这一切都很好,因此不会出现编译错误

。 /code>),这个简单的赋值没有类型转换


,那么为什么他们这样定义它?

我认为原因是让这样的例子有效:

    byte b = ...
    b += 1;

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

    b += (byte) 1;

The compound assignment operators are specified by the JLS (15.26.2) as follows:

"A compound assignment expression of the form E1 op= E2 is equivalent to

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

where T is the type of E1, except that E1 is evaluated only once."

In this case E1 is of type int E2 is of type long, and op is +. So this is equivalent to:

value = (int)(value + increment);

The addition of an int and a long gives a long that is then cast back to an int before assignment. That is all fine, hence no compilation error.

The difference between this and the simple assignment (i.e. value = value + increment;), is that the simple assignment doesn't have a typecast.


OK, so why did they define it this way?

I think that the reason is to make examples like this work:

    byte b = ...
    b += 1;

Without the typecast, b += 1 would be a compilation error and you'd need to write it as:

    b += (byte) 1;
少女七分熟 2024-11-03 06:38:42

这个链接已经分析了你提出的问题。

不同的行为可能导致精度损失

为避免发生不愉快的意外,请勿
使用复合赋值运算符
byte、short 或类型的变量
字符。使用复合赋值时
int 类型变量上的运算符,
确保表达式
右侧不是 long 类型,
浮动或双倍。使用复合时
变量的赋值运算符
类型float,确保表达式
右侧的不是类型
双倍的。这些规则足以
阻止编译器生成
危险的狭窄铸型。

This link has analyzed the problem you have brought up.

Varying behavior for possible loss of precision

To avoid unpleasant surprises, do not
use compound assignment operators on
variables of type byte, short, or
char. When using compound assignment
operators on variables of type int,
ensure that the expression on the
right-hand side is not of type long,
float, or double. When using compound
assignment operators on variables of
type float, ensure that the expression
on the right-hand side is not of type
double. These rules are sufficient to
prevent the compiler from generating
dangerous narrowing casts.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文