变化的行为可能导致精度损失
在Java中,当你这样做时
int b = 0;
b = b + 1.0;
您可能会失去精度错误。 但是,如果你这样做,为什么呢?
int b = 0;
b += 1.0;
没有任何错误?
那是因为b += 1.0;
相当于b = (int) ((b) + (1.0));
。 缩小基元转换(JLS 5.1.3)隐藏在复合赋值操作中。
JLS 15.26.2复合赋值操作符(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”中的Puzzle 9:Tweedledum的主题。 以下是本书的一些摘录(为简洁起见,稍作编辑):
许多程序员认为x += i;
只是x = x + i;
的简写x = x + i;
。 这不太正确:如果结果的类型比变量的类型宽,则复合赋值运算符执行静默缩小基元转换。
为避免不愉快的意外, 不要对 byte
, short
或char
类型的变量使用复合赋值操作符 。 在int
类型的变量上使用复合赋值运算符时,请确保右侧的表达式不是long
类型, float
类型或double
类型的类型。 在float
类型的变量上使用复合赋值运算符时,请确保右侧的表达式不是double
类型。 这些规则足以防止编译器产生危险的缩小转换。
对于语言设计师来说,复合赋值操作符产生不可见的演员可能是一个错误; 其中变量的类型比计算结果更窄的复合赋值应该是非法的。
最后一段值得注意:C#在这方面比较严格(请参阅C#语言规范7.13.2复合赋值)。
也许,也许是因为在前者将b转换为浮点,然后添加,然后将其转换回整数?
而后者可能会将1.0转换为整数,并进行整数加法?
只是一个猜测。
链接地址: http://www.djcxy.com/p/73635.html上一篇: Varying behavior for possible loss of precision
下一篇: Does Java compiler recognize byte and short as literals?