謎題10:八兩
與上面的例子相反,如果我們給出的關於變量x和i的聲明是如下的合法語句:
x = x + i;
但是,它並不是:
x += i;
乍一看,這個謎題可能看起來與前面一個謎題相同。但是請放心,它們並不一樣。這兩個謎題在哪一條語句必是合法的,以及哪一條語句必是不合法的方面,正好相反。
就像前面的謎題一樣,這個謎題也依賴於有關復合賦值操作符的規範中的細節。二者的相似之處就此打住。基於前面的謎題,你可能會想:符合賦值操作符比簡單賦值操作符的限制要少一些。在一般情況下,這是對的,但是有這麽一個領域,在其中簡單賦值操作符會顯得更寬松一些。
復合賦值操作符要求兩個操作數都是原始類型的,例如int,或包裝了的原始類型,例如Integer,但是有一個例外:如果在+=操作符左側的操作數是String類型的,那麽它允許右側的操作數是任意類型,在這種情況下,該操作符執行的是字符串連接操作。簡單賦值操作符(=)允許其左側的是對象引用類型,這就顯得要寬松許多了:你可以使用它們來表示任何你想要表示的內容,只要表達式的右側與左側的變量是賦值兼容的即可。
你可以利用這一差異來解決該謎題。要想用 += 操作符來執行字符串連接操作,你就必須將左側的變量聲明為String類型。通過使用直接賦值操作符,字符串連接的結果可以存放到一個Object類型的變量中。
為了說得具體一些,並提供一個解決方案給這個謎題,假設我們在該謎題的兩個賦值表達式之前有下面這些聲明:
Object x = "Buy ";
String i = "Effective Java!";
簡單賦值是合法的,因為 x + i 是String類型的,而String類型又是與Object賦值兼容的:
x = x + i;
復合賦值是非法的,因為左側是一個Object引用類型,而右側是一個String類型:
x += i;
這個謎題對程序員來說幾乎算不上什麽教訓。對語言設計者來說,加法的復合賦值操作符應該在右側是String類型的情況下,允許左側是Object類型。這項修改將根除這個謎題所展示的違背直覺的行為。
謎題10:八兩