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