Java更多的類謎題68:灰色的陰影

字號(hào):

下面的程序在相同的范圍內(nèi)具有兩個(gè)名字相同的聲明,并且沒有任何明顯的方式可以在它們二者之間做選擇。這個(gè)程序會(huì)打印Black嗎?它會(huì)打印White嗎?甚至,它是合法的嗎?
    public class ShadesOfGray {
     public static void main(String[] args){
     System.out.println(X.Y.Z);
     }
    }
    class X {
     static class Y {
     static String Z = "Black";
     }
     static C Y = new C();
    }
    class C {
     String Z = "White";
    }
    沒有任何顯而易見的方法可以確定該程序應(yīng)該打印Black還是White。編譯器通常會(huì)拒絕模棱兩可的程序,而這個(gè)程序看起來肯定是模棱兩可的。因此,它似乎應(yīng)該是非法的。如果你試著運(yùn)行它,就會(huì)發(fā)現(xiàn)它是合法的,并且會(huì)打印出White。你怎樣才能事先了解這一切呢?
    可以證明,在這樣的上下文環(huán)境中,有一條規(guī)則決定著程序的行為,即當(dāng)一個(gè)變量和一個(gè)類型具有相同的名字,并且它們位于相同的作用域時(shí),變量名具有優(yōu)先權(quán)[JLS 6.5.2]。變量名將遮掩(obscure)類型名[JLS 6.3.2]。相似地,變量名和類型名可以遮掩包名。這條規(guī)則真的是相當(dāng)?shù)鼗逎?,任何依賴于它的程序都極有可能使它的讀者暈頭轉(zhuǎn)向。
    幸運(yùn)的是,遵守標(biāo)準(zhǔn)的Java命名習(xí)慣的程序繼續(xù)從來都不會(huì)遇上這個(gè)問題。類應(yīng)該以一個(gè)大寫字母開頭,以MixedCase的形式書寫;變量應(yīng)該以一個(gè)小寫字母開頭,以mixedCase的形式書寫;而常量應(yīng)該以一個(gè)大寫字母開頭,以ALL_CAPS的方式書寫。單個(gè)的大寫字母只能用于類型參數(shù),就像在泛型接口Map中那樣。包名應(yīng)該以lower.case的方式命名[JLS 6.8]。
    為了避免常量名與類名的沖突,在類名中應(yīng)該將首字母縮拼詞當(dāng)作普通的詞處理[EJ Item 38]。例如,一個(gè)表示全局標(biāo)識(shí)符的類應(yīng)該被命名為Uuid,而不是UUID,盡管其首字母縮拼詞通常被寫為UUID。(Java平臺(tái)庫就違反了這項(xiàng)建議,因?yàn)樗哂蠻UID、URL和URI這樣的類名。)為了避免變量名與包名的沖突,請(qǐng)不要使用頂層的包名或領(lǐng)域名作為變量的名字,特別是不要將一個(gè)變量命名為com、org、net、edu、java或javax。
    要想移除ShadesOfGray這個(gè)程序中的所有不明確性,只需以遵守命名習(xí)慣的方式對(duì)其重寫即可。很明顯,下面的程序?qū)⒋蛴lack。作為一種附加的好處,當(dāng)你大聲朗讀這個(gè)程序時(shí),聽起來還最初的那個(gè)程序是完全一樣的。
    public class ShadesOfGray {
     public static void main(String[ ] args){
     System.out.println(Ex.Why.Z);
     }
    }
    class Ex {
     static class Why {
     static String Z = "Black";
     }
     static See y = new See();
    }
    class See {
     String Z = "White";
    }
    總之,應(yīng)該遵守標(biāo)準(zhǔn)的命名習(xí)慣以避免不同的命名空間之間的沖突,還有一個(gè)原因就是如果你違反這些習(xí)慣,那么你的程序?qū)⒆屓穗y以辨認(rèn)。同樣,為了避免變量名與通用的頂層包名相沖突,請(qǐng)使用MixedCase風(fēng)格的類名,即使其名字是首字母縮拼詞也應(yīng)如此。通過遵守這些規(guī)則,你就可以確保你的程序永遠(yuǎn)不會(huì)遮掩類名或包名。再次說明一下,這里列舉的仍然是你應(yīng)該在覆寫之外的情況中避免名字重用的一個(gè)實(shí)例。對(duì)語言設(shè)計(jì)者來說,應(yīng)該考慮去消除遮掩的可能性。C#是通過將域和嵌套類置于相同的命名空間來實(shí)現(xiàn)這一點(diǎn)的。