在任何程序設計語言中,一項重要的特性就是名字的運用。我們創建一個對象時,會分配到一個保存區域的名字。方法名代表的是一種具體的行動。通過用名字描述自己的系統,可使自己的程序更易人們理解和修改。它非常象寫散文——目的是與讀者溝通。
我們用名字引用或描述所有對象與方法。若名字選得好,可使自己及其他人更易理解自己的代碼。
將人類語言中存在細致差別的概念“映射”到一種程序設計語言中時,會出現一些特殊的問題。在日常生活中,我們用相同的詞表達多種不同的含義——即詞的“過載”。我們說“洗襯衫”、“洗車”以及“洗狗”。但若強制象下面這樣說,就顯得很愚蠢:“襯衫洗 襯衫”、“車洗 車”以及“狗洗 狗”。這是由於聽眾根本不需要對執行的行動作任何明確的區分。人類的大多數語言都具有很強的“冗余”性,所以即使漏掉了幾個詞,仍然可以推斷出含義。我們不需要獨一無二的標識符——可從具體的語境中推論出含義。
大多數程序設計語言(特別是C)要求我們為每個函數都設定一個獨一無二的標識符。所以絕對不能用一個名為print()的函數來顯示整數,再用另一個print()顯示浮點數——每個函數都要求具備唯一的名字。
在Java裡,另一項因素強迫方法名出現過載情況:構建器。由於構建器的名字由類名決定,所以只能有一個構建器名稱。但假若我們想用多種方式創建一個對象呢?例如,假設我們想創建一個類,令其用標准方式進行初始化,另外從文件裡讀取信息來初始化。此時,我們需要兩個構建器,一個沒有自變量(默認構建器),另一個將字串作為自變量——用於初始化對象的那個文件的名字。由於都是構建器,所以它們必須有相同的名字,亦即類名。所以為了讓相同的方法名伴隨不同的自變量類型使用,“方法過載”是非常關鍵的一項措施。同時,盡管方法過載是構建器必需的,但它亦可應用於其他任何方法,且用法非常方便。
在下面這個例子裡,我們向大家同時展示了過載構建器和過載的原始方法:
//: Overloading.java // Demonstration of both constructor // and ordinary method overloading. import java.util.*; class Tree { int height; Tree() { prt("Planting a seedling"); height = 0; } Tree(int i) { prt("Creating new Tree that is " + i + " feet tall"); height = i; } void info() { prt("Tree is " + height + " feet tall"); } void info(String s) { prt(s + ": Tree is " + height + " feet tall"); } static void prt(String s) { System.out.println(s); } } public class Overloading { public static void main(String[] args) { for(int i = 0; i < 5; i++) { Tree t = new Tree(i); t.info(); t.info("overloaded method"); } // Overloaded constructor: new Tree(); } } ///:~
Tree既可創建成一顆種子,不含任何自變量;亦可創建成生長在苗圃中的植物。為支持這種創建,共使用了兩個構建器,一個沒有自變量(我們把沒有自變量的構建器稱作“默認構建器”,注釋①),另一個采用現成的高度。
①:在Sun公司出版的一些Java資料中,用簡陋但很說明問題的詞語稱呼這類構建器——“無參數構建器”(no-arg constructors)。但“默認構建器”這個稱呼已使用了許多年,所以我選擇了它。
我們也有可能希望通過多種途徑調用info()方法。例如,假設我們有一條額外的消息想顯示出來,就使用String自變量;而假設沒有其他話可說,就不使用。由於為顯然相同的概念賦予了兩個獨立的名字,所以看起來可能有些古怪。幸運的是,方法過載允許我們為兩者使用相同的名字。