這個謎題将測試你對條件操作符的掌握程度,這個操作符有一個更廣為人知的名
字:問号冒号操作符。下面的程式将會列印出什麼呢?
public class DosEquis{
public static void main(String[] args){
char x = 'X' ;
int i = 0;
System.out.println(true ? x : 0);
System.out.println(false ? i : x);
}
}
這個程式由兩個變量聲明和兩個print 語句構成。第一個print 語句計算條件表
達式(true ? x : 0)并列印出結果,這個結果是char類型變量 x 的值’X’。而
第二個print 語句計算表達式(false ? i : x)并列印出結果,這個結果還是依
舊是’X’的x,是以這個程式應該列印 XX。然而,如果你運作該程式,你就會
發現它列印出來的是X88。這種行為看起來挺怪的。第一個print 語句列印的是
X,而第二個列印的卻是88。它們的不同行為說明了什麼呢?
答案就在規範有關條件表達式部分的一個陰暗的角落裡。請注意在這兩個表達式
中,每一個表達式的第二個和第三個操作數的類型都不相同:x 是 char類型的,
而 0 和 i 都是 int類型的。就像在謎題 5 的解答中提到的,混合類型的計算會引
起 混亂,而這一點比在條件表達式中比在其它任何地方都表現得更 明顯。你可能
考慮過,這個程式中兩個條件表達式的結果類型是相同的,就像它們的操作數類
型是相同的一樣,盡管操作數的順序颠倒了一下,但是實際情況并非如此。
确定條件表達式結果類型的規則過于冗長和複雜,很難完全記住它們,但是其核
心就是一下三點:
* 如果第二個和第三 個操作數具有相同的類型,那麼它就是條件表達式的類
型。換句話說,你可以通過繞過混合類型的計算來避免大麻煩 。
* 如果一個操作數的類型是 T,T 表示 byte、short 或 char,而另 一個操作
數是一個 int 類型的常量表達式,它的值是可以用類型 T 表示的,那麼條
件表達式的類型就是 T。
* 否則,将對操作數類型運用二進制數字提升,而條件表達式的類型就是第
二個和第三個操作數被提升之後的類型。
2、3 兩點對本謎題是關鍵。在程式的兩個條件表達式中,一個操作數的類型是
char,另一個的類型是 int。在兩個表達式中,int 操作數都是0,它可以被表
示成一個 char。然而,隻有第一個表達式中的 int 操作數是常量 (0),而第二
個表達式中的 int 操作數是變量 (i)。是以,第 2 點被應用到了第 一個表達式
上,它傳回的類型是 char,而第 3 點被應用到了第二個表達式上,其傳回的類
型是對 int 和 char 運用了二進制數字提升之後的類型,即 int。
條件表達式的類型将确定哪一個重載的print 方法将被調用。對第一個表達式來
說,PrintStream.print(char)将被調用,而對第二個表達式來說,
PrintStream.print(int)将被調用。前一個重載方法将變量 x 的值作為Unicode
字元 (X)來列印,而後一個重載方法将其作為一個十進制整數 (88)來列印。
至此,謎題被解開了。
總之,通常最好是在條件表達式中使用類型相同的第二和第三操作數。否則,你
和你的程式的讀者必須要徹底了解這些表達式行為的複雜規範。
對語言設計者來說,也許可以設計一個犧牲掉了部分靈活性,但是增加了簡潔性
的條件操作符。例如,要求第二和第三操作數必須就有相同的類型,這看起來就
很合理。或者,條件操作符可以被定義為對常量沒有任何特殊處理。為了讓這些
選擇對程式員來說更加容易接受,可以提供用來表示所有原始類型字面常量的語
法。這也許确實是一個好注意,因為它增加了語言的一緻性和完備性,同時又減
少了對轉型的需求。