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

a C*_*CVn 8 java variable-assignment compound-operator

我发现Java的+ =, - =,*=,/ =复合赋值运算符(好问题:)),但它有一部分我不太明白.借用这个问题:

int i = 5;
long l = 8;
Run Code Online (Sandbox Code Playgroud)

然后i = i + l;将不会编译但i += l;将编译正常.

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

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

这给出i += l;了与仅评估一次i = (int)((i) + (l));的异常相同的内容i.

A long可能(IIRC甚至保证)长于a int,因此可以保持更大范围的值.

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

Ern*_*ill 14

基本上,因为i += l编译好像是编写的i = (int) (i + l).向intbytechar变量添加值时有类似的"惊喜" - 赋值运算符有效,而普通加法运算符则不然.

  • 已经在上面提到的问题的接受答案中解释了这一点.我想OP的意思是这种隐式缩小转换可能导致数据丢失,编译器可能(应该)至少警告这一点. (2认同)

Bil*_*ard 8

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

正如您所说,它可能应该是编译时错误或至少是警告.我所知道的大多数书籍和教程x += y;都是速记的x = x + y;.老实说,我不知道在第15.26.2节中除了一个JLS的化合物分配操作员之外的任何区别.

Java Puzzlers的第2章(谜题9):陷阱,陷阱和角落案例中,作者(Joshua Bloch和Neal Gafter)要求您提供声明x并且i这是一个法律声明:

x += i;
Run Code Online (Sandbox Code Playgroud)

这不是:

x = x + i;
Run Code Online (Sandbox Code Playgroud)

有很多解决方案,包括您在问题中发布的前两行代码.作者警告不要使用复合赋值运算符的类型的变量byte,shortchar,并建议使用的类型的变量,这些运营商的时候int,你应该确保在RHS表达式不是long,floatdouble.

他们总结了以下观点(强调我的):

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