Java庫謎題63:更多同樣的問題

字號:

下面的程序除了是面向對象的這一點之外,與前一個非常相似。因為從前一個程序中已經(jīng)吸取了教訓,這個程序使用了一個通用目的的Map實現(xiàn),即一個HashMap,來替代前一個程序的IdentityHashMap。那么,這個程序會打印出什么呢?
    import java.util.*;
    public class MoreNames {
     private Map m = new HashMap();
     public void MoreNames() {
     m.put("Mickey", "Mouse");
     m.put("Mickey", "Mantle");
     }
     public int size() {
     return m.size();
     }
     public static void main(String args[ ]) {
     MoreNames moreNames = new MoreNames();
     System.out.println(moreNames.size());
     }
    }
    這個程序看起來很直觀,其main方法通過調用無參數(shù)的構造器創(chuàng)建了一個MoreNames實例。這個MoreNames實例包含一個私有的Map域(m),它被初始化成一個空的HashMap。該無參數(shù)的構造器似乎將兩個映射關系放置到了映射表m中,這兩個映射關系都具有相同的鍵(Mickey)。我們從前一個謎題已知,棒球手(Mickey Mantle)應該覆蓋嚙齒明星(Mickey Mouse),從而只留下一個映射關系。main方法之后在MoreNames實例上調用了size方法,它會調用映射表m上的size方法,并返回結果,我們假設其為1。這種分析還剩下一個問題:該程序打印的是0而不是1。這種分析出了什么錯呢?
    問題在于MoreNames沒有任何程序員聲明的構造器。它擁有的只是一個返回值為void的實例方法,即MoreNames,作者可能是想讓它作為構造器的。遺憾的是,返回類型(void)的出現(xiàn)將想要的構造器聲明變成了一個方法聲明,而且該方法永遠都不會被調用。因為MoreNames沒有任何程序員聲明的構造器,所以編譯器會幫助(真的是在幫忙嗎?)生成一個公共的無參數(shù)構造器,它除了初始化它所創(chuàng)建的域實例之外,不做任何事情。就像前面提到的,m被初始化成了一個空的HashMap。當在這個HashMap上調用size方法時,它將返回0,這正是該程序打印出來的內容。
    訂正該程序很簡單,只需將void返回類型從MoreNames聲明中移除即可,這將使它從一個實例方法聲明變成一個構造器聲明。通過這種修改,該程序就可以打印出我們所期望的1。
    本謎題的教訓是:不要因為偶然地添加了一個返回類型,而將一個構造器聲明變成了一個方法聲明。盡管一個方法的名字與聲明它的類的名字相同是合法的,但是你千萬不要這么做。更一般地講,要遵守標準的命名習慣,它強制要求方法名必須以小寫字母開頭,而類名應該以大寫字母開頭。
    對語言設計者來說,在沒有任何程序員聲明的構造器的情況下,自動生成一個缺省的構造器這種做法并非是一個很好的主意。如果確實生成了這樣的構造器,也許應該讓它們是私有的。有好幾種其他的方法可以消除這個陷阱。一種方法是禁止方法名與類名相同,就像C#所作的那樣,另一種是徹底消滅所有的構造器,就像Smalltalk所作的那樣。