谜题9:半斤
该谜题仅有两行代码:
x+=i; //合法
x = x + i; //不合法
对于上面的两个表达式,我们通常都认为第一个表达式是第二个表达式的简写方式,但这并不准确。这两个表达式都被称为赋值表达式。第二个表达式使用的是简单赋值操作符(=),而第一个表达式使用的是复合赋值操作符。在java语言规范中提到,复合赋值等价于简单赋值 E1 = (T)((E1) op (E2)),其中T是E1的类型,除非E1只被计算一次。也就是说,复合赋值表达式自动地将所执行计算的结果转型为其左侧变量的类型。如果结果的类型与该变量的类型相同,则不会有任何影响;若结果的类型比该变量要宽,那么复合赋值操作符将会执行一个窄化原生类型转换,因此,上面的第二个表达式可能会产生一个编译错误。我们可以假设上面代码中的类型如下:
short x = 0;
int i = 123456;
那么 x+=i 将不会产生任何错误,但打印的值却不是123456,而是-7616,因为int类型的数值123456对于short来说太大了,自动产生的转型把int数值的高两位截除了。而对于简单赋值来说,这是非法的,需要我们添加一个显示的转型。总的来说,复合赋值表达式可能是危险的,我们应当避免将复合赋值操作符作用于byte、short或char类型的变量。在将复合赋值操作符作用于int类型的变量时,要确保表达式右侧不是long、float或double类型。在将复合赋值操作符作用于float类型的变量时,要确保表达式右侧不是double类型。这些规则足以防止编译器产生危险的窄化转型,因为复合赋值操作符总是会悄悄地产生一个转型,而这样的转型有可能会悄悄地丢失掉精度或数量值。