我们给出一个对变量x和i的声明即可,它肯定是一个合法的语句:
x += i;
但是,它并不是:
x = x + i;
许多程序员都会认为该迷题中的第一个表达式(x += i)只是第二个表达式(x = x + i)的简写方式。但是这并不十分准确。这两个表达式都被称为赋值表达式。第二条语句使用的是简单赋值操作符(=),而第一条语句使用的是复合赋值操作符。(复合赋值操作符包括 +=、-=、*=、/=、%=、<<=、>>=、>>>=、&=、^=和|=)Java语言规范中讲到,复合赋值 E1 op= E2等价于简单赋值E1 = (T)((E1)op(E2)),其中T是E1的类型,除非E1只被计算一次。
换句话说,复合赋值表达式自动地将它们所执行的计算的结果转型为其左侧变量的类型。如果结果的类型与该变量的类型相同,那么这个转型不会造成任何影响。然而,如果结果的类型比该变量的类型要宽,那么复合赋值操作符将悄悄地执行一个窄化原始类型转换。因此,我们有很好的理由去解释为什么在尝试着执行等价的简单赋值可能会产生一个编译错误。
为了说得具体一些,并提供一个解决方案给这个谜题,假设我们在该谜题的两个赋值表达式之前有下面这些声明:
short x = 0;
int i = 123456;
复合赋值编译将不会产生任何错误:
x += i; // 包含了一个隐藏的转型!
你可能期望x的值在这条语句执行之后是123,456,但是并非如此l,它的值是-7,616。int类型的数值123456对于short来说太大了。自动产生的转型悄悄地把int数值的高两位给截掉了。这也许就不是你想要的了。
相对应的简单赋值是非法的,因为它试图将int数值赋值给short变量,它需要一个显式的转型:
x = x + i; // 不要编译——“可能会丢掉精度”
这应该是明显的,复合赋值表达式可能是很危险的。为了避免这种令人不快的突袭,请不要将复合赋值操作符作用于byte、short或char类型的变量上。在将复合赋值操作符作用于int类型的变量上时,要确保表达式右侧不是long、float或double类型。在将复合赋值操作符作用于float类型的变量上时,要确保表达式右侧不是double类型。这些规则足以防止编译器产生危险的窄化转型。
总之,复合赋值操作符会悄悄地产生一个转型。如果计算结果的类型宽于变量的类型,那么所产生的转型就是一个危险的窄化转型。这样的转型可能会悄悄地丢弃掉精度或数量值。对语言设计者来说,也许让复合赋值操作符产生一个不可见的转型本身就是一个错误;对于在复合赋值中的变量类型比计算结果窄的情况,也许应该让其非法才对。
分享到:
相关推荐
一本很好的java参考书,帮助你解决java中的很多注意不到的问题。
在JDK1.2中,Thread.stop、Thread.suspend以及其他许多线程相关的方法都因为它们不安全而不推荐使用了。下面的方法展示了你用Thread.stop可以实现的可怕事情之一
java中一些疑难问题的剖析,对初学java者有很好的帮助。
java解惑java解惑java解惑java解惑java解惑java解惑
Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑Java解惑
这篇文档主要是介绍各种大家需要注意的java各种语法细节。希望对大家有所帮助。写的比较幽默。类似“十六进制的趣事”这种问题,估计在SSH大行其道的情况下,有些细节大家都不太关注了。
java中最容易被忽略的地方. 博文链接:https://justjavac.iteye.com/blog/175252
表达式之谜,符号之谜,循环之谜,异常之谜,类之谜,库之谜,各种谜题。
《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》《Java解惑》
Java解惑.pdf Java解惑.pdf Java解惑.pdf Java解惑.pdf
Java解惑中文版 Java解惑 java健壮程序
JAVA解惑.pdf JAVA解惑.pdf JAVA解惑.pdf
与java相关的的学习,适合初学者,可以看看
Java PUZZLE Java 解惑 Java PUZZLE Java 解惑 Java PUZZLE Java 解惑Java PUZZLE Java 解惑 Java PUZZLE Java 解惑 Java PUZZLE Java 解惑
比较容易混淆的java面试题,看看对笔试面试有一定的帮助。
JAVA解惑,你面包括一些java经典的问题。
《Java解惑》 布洛克 著;陈昊鹏 译 扫描清晰带目录,仅供参阅,请支持正版