天天看點

Java解惑 - 半斤八兩(1)

我們給出一個對變量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類型。這些規則足以防止編譯器産生危險的窄化轉型。

    總之,複合指派操作符會悄悄地産生一個轉型。如果計算結果的類型寬于變量的類型,那麼所産生的轉型就是一個危險的窄化轉型。這樣的轉型可能會悄悄地丢棄掉精度或數量值。對語言設計者來說,也許讓複合指派操作符産生一個不可見的轉型本身就是一個錯誤;對于在複合指派中的變量類型比計算結果窄的情況,也許應該讓其非法才對。