對於方法的創建,可將其想象成為自己寫的每個類都調用一次initialize()。這個名字提醒我們在使用對象之前,應首先進行這樣的調用。但不幸的是,這也意味著用戶必須記住調用方法。在Java中,由於提供了名為“構建器”的一種特殊方法,所以類的設計者可擔保每個對象都會得到正確的初始化。若某個類有一個構建器,那麼在創建對象時,Java會自動調用那個構建器——甚至在用戶毫不知覺的情況下。所以說這是可以擔保的!
接著的一個問題是如何命名這個方法。存在兩方面的問題。第一個是我們使用的任何名字都可能與打算為某個類成員使用的名字沖突。第二是由於編譯器的責任是調用構建器,所以它必須知道要調用是哪個方法。C++采取的方案看來是最簡單的,且更有邏輯性,所以也在Java裡得到了應用:構建器的名字與類名相同。這樣一來,可保證象這樣的一個方法會在初始化期間自動調用。
下面是帶有構建器的一個簡單的類(若執行這個程序有問題,請參考第3章的“賦值”小節)。
//: SimpleConstructor.java // Demonstration of a simple constructor package c04; class Rock { Rock() { // This is the constructor System.out.println("Creating Rock"); } } public class SimpleConstructor { public static void main(String[] args) { for(int i = 0; i < 10; i++) new Rock(); } } ///:~
現在,一旦創建一個對象:
new Rock();
就會分配相應的存儲空間,並調用構建器。這樣可保證在我們經手之前,對象得到正確的初始化。
請注意所有方法首字母小寫的編碼規則並不適用於構建器。這是由於構建器的名字必須與類名完全相同!
和其他任何方法一樣,構建器也能使用自變量,以便我們指定對象的具體創建方式。可非常方便地改動上述例子,以便構建器使用自己的自變量。如下所示:
class Rock { Rock(int i) { System.out.println( "Creating Rock number " + i); } } public class SimpleConstructor { public static void main(String[] args) { for(int i = 0; i < 10; i++) new Rock(i); } }
利用構建器的自變量,我們可為一個對象的初始化設定相應的參數。舉個例子來說,假設類Tree有一個構建器,它用一個整數自變量標記樹的高度,那麼就可以象下面這樣創建一個Tree對象:
tree t = new Tree(12); // 12英尺高的樹
若Tree(int)是我們唯一的構建器,那麼編譯器不會允許我們以其他任何方式創建一個Tree對象。
構建器有助於消除大量涉及類的問題,並使代碼更易閱讀。例如在前述的代碼段中,我們並未看到對initialize()方法的明確調用——那些方法在概念上獨立於定義內容。在Java中,定義和初始化屬於統一的概念——兩者缺一不可。
構建器屬於一種較特殊的方法類型,因為它沒有返回值。這與void返回值存在著明顯的區別。對於void返回值,盡管方法本身不會自動返回什麼,但仍然可以讓它返回另一些東西。構建器則不同,它不僅什麼也不會自動返回,而且根本不能有任何選擇。若存在一個返回值,而且假設我們可以自行選擇返回內容,那麼編譯器多少要知道如何對那個返回值作什麼樣的處理。