为什么我+ = l编译,其中我是int而l是长?

时间:2012-01-03 14:03:38

标签: java variable-assignment compound-operator

我发现Java's +=, -=, *=, /= compound assignment operators(好问题:)),但它有一部分我不太明白。借用这个问题:

int i = 5;
long l = 8;
     

然后i = i + l;将无法编译,但i += l;将编译正常。

联系问题的接受答案表明:

  

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

,其中i += l;i = (int)((i) + (l));相同,但i仅评估一次。

long可能(IIRC甚至可以保证)长于int,因此可以保留更大范围的值。

鉴于这种情况很容易导致数据丢失,因为在执行语句(r值表达式评估或赋值)期间的某些时刻必须缩小转换,为什么i += l;不是编译时错误或至少是警告?

3 个答案:

答案 0 :(得分:14)

基本上,因为编译i += l就像编写i = (int) (i + l)一样。将int值添加到bytechar变量时会出现类似的“意外” - 赋值运算符可以正常工作,而普通加法运算符则不然。

答案 1 :(得分:8)

  

鉴于这种情况很容易导致数据丢失,因为在执行语句(r值表达式评估或赋值)期间的某些时刻必须缩小转换,为什么i + = l;不是编译时错误或至少是警告?

正如您所说,它应该是编译时错误或至少是警告。我所知道的大多数书籍和教程都以x += y;作为x = x + y;的简写。老实说,除了一个JLS的15.26.2 Compound Assignment Operators部分之外,我不知道有任何区别。

Java Puzzlers: Traps, Pitfalls, and Corner Cases的第2章(谜题9)中,作者(Joshua Bloch& Neal Gafter)要求您提供xi的声明,以便这是一份法律声明:

x += i;

而这不是:

x = x + i;

有很多解决方案,包括您在问题中发布的前两行代码。作者警告不要在byteshortchar类型的变量上使用复合赋值运算符,并建议在类型为int的变量上使用这些运算符时确保RHS表达式不是longfloatdouble

他们总结以下观察结果(强调我的):

  

总之,复合赋值运算符以静默方式生成强制转换。如果计算结果的类型比变量的类型宽,则生成的转换是危险的缩小转换。这样的演员可以默默地丢弃精确度或幅度。 对于语言设计者来说,复合赋值运算符生成隐形强制转换可能是一个错误。复合赋值,其中变量的类型比计算结果的范围窄,应该是非法的。

答案 2 :(得分:1)

原因是你可以这样做:

byte b = 1;

b += 1;

如果+ =扩展为b = b + 1,则表达式不会进行类型检查,因为表达式“b + 1”的类型为int。即使你一起添加两个字节,java中的所有整数表达式至少都是int类型。

public class Test {
  public static void main(String[] args) {
    byte b = 1;
    byte c = 2;
    byte d = b + c;
  }
}


Test.java:5: possible loss of precision
found   : int
required: byte
    byte d = b + c;
               ^
1 error