Java高級謎題86:有毒的括號垃圾

字號:

你能否舉出這樣一個(gè)合法的Java表達(dá)式,只要對它的某個(gè)子表達(dá)式加上括號就可以使其成為不合法的表達(dá)式,而添加的括號只是為了注解未加括號時(shí)賦值的順序?
    插入一對用來注解現(xiàn)有賦值順序的括號對程序的合法性似乎是應(yīng)該沒有任何影響的。事實(shí)上,絕大多數(shù)情況下確實(shí)是沒有影響的。但是,在兩種情況下,插入一對看上去沒有影響的括號可能會(huì)令合法的Java程序變得不合法。這種奇怪的情況是由于數(shù)值的二進(jìn)制補(bǔ)碼的不對稱性引起的,就像在謎題33和謎題64中所討論的那樣。 你可能會(huì)聯(lián)想到,最小的int型負(fù)數(shù)其絕對值比的int型正數(shù)大1:Integer.MIN_VALUE是-231,即-2,147,483,648,而Integer.MAX_VALUE是231-1,即2,147,483,647。
    Java不支持負(fù)的十進(jìn)制字面常量;int和long類型的負(fù)數(shù)常量都是由正數(shù)十進(jìn)制字面常量前加一元負(fù)操作符(-)構(gòu)成。這種構(gòu)成方式是由一條特殊的語言規(guī)則所決定的:在int類型的十進(jìn)制字面常量中,的是2147483648。而從0到2147483647的所有十進(jìn)制字面常量都可以在任何能夠使用int類型字面常量的地方出現(xiàn),但是字面常量2147483648只能作為一元負(fù)操作符的操作數(shù)來使用[JLS 3.10.1]。
    一旦你知道了這個(gè)規(guī)則,這個(gè)謎題就很容易了。符號-2147483648構(gòu)成了一個(gè)合法的Java表達(dá)式,它由一元負(fù)操作符加上一個(gè)int型字面常量 2147483648組成。通過添加一對括號來注解(很不重要的)賦值順序,即寫成-(2147483648),就會(huì)破壞這條規(guī)則。信不信由你,下面這個(gè)程序肯定會(huì)出現(xiàn)一個(gè)編譯期錯(cuò)誤,如果去掉了括號,那么錯(cuò)誤也就沒有了:
    public class PoisonParen {
     int i = -(2147483648);
    }
    類似地,上述情況也適用于long型字面常量。下面這個(gè)程序也會(huì)產(chǎn)生一個(gè)編譯期錯(cuò)誤,并且如果你去掉括號錯(cuò)誤也會(huì)消失:
    public class PoisonParen {
    long j = -(9223372036854774808L);
    }