Java 的複合运算是大家常用的运算, 不过有一个细节可能一般的教学文章不会提到, 这可能会让你遇到莫名其妙的错误。
複合运算并不等于一般运算加设定运算
有些教学文章会说複合运算就等于拆解开来的一般运算加上设定运算, 例如 a+=b
就等同于 a = a + b
, 不过这是有问题的, 请看以下範例:
jshell> short s = 2s ==> 2jshell> s = s + 2| Error:| incompatible types: possible lossy conversion from int to short| s = s + 2| ^---^jshell>jshell> s += 2$36 ==> 4
你可以看到应该是同样的运算以複合运算没问题, 但是不用複合运算却出错?从错误讯息可以看出来, 因为 2 是 int
, 所以进行加法运算时, 会把 short 型别的 s 放宽转型成 int, 但是当要把计算结果放回 s 时, 就会发生无法自动从 int 缩窄转成 short 的错误。
但是複合运算却不会发生这样的问题, 这很明显告诉我们两种运算并不完全相同。
複合运算隐含了强制转型
如果你查看 Java 语言的规格书, 就会发现複合运算的说明如下:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
也就是说, 複合运算在设定之前, 会强制将运算结果转型回变数的型别, 因此前面複合运算的版本其实等同以下程式码:
jshell> s = (short)(s + 2)
由于加上了强制运算, 所以原本 int 型别的计算结果就会被强制转回範围较窄的 short 型别, 不会发生错误了。
当然, 因为这样的机制, 也要注意複合运算可能会溢位, 例如:
jshell> s *= 10000$39 ==> -5536jshell> ss ==> -5536
小结
学习程式语言时, 很容易因为程式可以得到正确结果而忽略了其中的细节, 本文仅是其中的一个小例子, 提醒大家要多留意, 否则遇到错误时往往无法找出真正的原因。