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

时间:2010-04-23 07:08:44

标签: java implicit-cast compound-assignment

在Java中,当你做

int b = 0;
b = b + 1.0;

您可能会丢失精度错误。但是为什么如果你这样做

int b = 0;
b += 1.0;

没有任何错误?

1 个答案:

答案 0 :(得分:34)

那是因为b += 1.0;相当于b = (int) ((b) + (1.0));narrowing primitive conversion (JLS 5.1.3)隐藏在复合赋值操作中。

JLS 15.26.2 Compound Assignment Operators(JLS第三版):

  

E1 op = E2 形式的复合赋值表达式等效于 E1 =(T)((E1)op(E2)),其中 T E1 的类型,但 E1 仅评估一次。

     

例如,以下代码是正确的:

short x = 3;
x += 4.6;
     

并导致x的值为7,因为它等同于:

short x = 3;
x = (short)(x + 4.6);

这也解释了为什么以下代码编译:

byte b = 1;
int x = 5;
b += x; // compiles fine!

但这不是:

byte b = 1;
int x = 5;
b = b + x; // DOESN'T COMPILE!

在这种情况下你需要明确地施放:

byte b = 1;
int x = 5;
b = (byte) (b + x); // now it compiles fine!

值得注意的是,复合作业中的隐含演员是精彩书籍Java Puzzlers拼图9:Tweedledum 的主题。以下是本书的一些摘录(为简洁起见略作编辑):

  

许多程序员认为x += i;只是x = x + i;的简写。这不完全正确:如果结果的类型比变量的类型宽,则复合赋值运算符执行静默缩小基元转换。

     

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

     

对于语言设计者来说,复合赋值运算符生成隐形强制转换可能是一个错误。复合赋值,其中变量的类型比计算结果的范围窄,应该是非法的。

最后一段值得注意的是:C#在这方面要严格得多(见C# Language Specification 7.13.2 Compound assignment)。