在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)), , 在哪里 tE1, , 除了那个 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!

值得注意的是,复合作业中的隐式演员是 难题9:Tweedledum 从精彩的书中 Java难题. 。以下是这本书的摘录(简洁地编辑):

许多程序员认为 x += i; 只是一个速记 x = x + i;. 。这并不是很正确:如果结果的类型比变量的类型宽,则复合分配操作员会执行静默狭窄的原始转换。

为了避免令人不愉快的惊喜, 请勿在类型变量上使用复合分配运算符 byte, short, , 或者 char. 。当在类型变量上使用复合分配运算符时 int, ,确保右侧的表达不为类型 long, float, , 或者 double. 。当在类型变量上使用复合分配运算符时 float, ,确保右侧的表达不为类型 double. 。这些规则足以防止编译器产生危险的狭窄铸件。

对于语言设计师来说,复合分配操作员生成隐形演员可能是一个错误。该变量具有比计算结果更窄类型的复合分配可能是非法的。

最后一段值得注意的是:C#在这方面更加严格(请参阅 C#语言规范7.13.2复合分配).

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top