# 建構子(constructor) 建構子(constructor) 建構子的英文為constructor,中文沒有統一的翻譯,通常稱為「建構子」、「建構式」、「建構元」或「建構函數」、「建構函式」…,都是在說同一個東西。 我們知道一個類別(class)內部定義了成員變數(JAVA的術語稱為成員屬性,或簡稱屬性(attribute))和成員函數(JAVA的術語稱為成員方法,或簡稱方法(method))。也就是說,類別定義了一些具體的屬性和方法,一旦類別做了實體化的動作之後(new關鍵字),就可以產生物件,這個(具體的)物件就會擁有該類別所定義的屬性、並且可以執行該類別所定義的方法。  註:此處先不討論靜態static的情況。 我們以實際的程式碼來說明,先定義一個類別: ```bash= class Student { // 定義一個類別,類別名稱為Student(學生) private: String studentID; // 宣告字串型態的學生證號 String gender; // 宣告字串型態的性別 int height; // 宣告整數型態的身高 public: int walk() // 定義此類別的方法walk() { 此方法的實作程式碼 } void say() // 定義此類別的方法say() { 此方法的實作程式碼 } 以上我們把Student這個類別定義好了,接下來我們要創造(具體的)學生物件,JAVA告訴我們語法要這麼寫: Student 小明 = new Student(); Student 阿華 = new Student(); Student 小美 = new Student(); 然後我們再把三人的基本資料填上去: 小明 . studentID = “L25247845”; 小明 . gender = “男”; 小明 . height = 175 ; 小華 . studentID = “L25267120”; 小華 . gender = “男”; 小華 . height = 182 ; 小美 . studentID = “L29627832”; 小美 . gender = “女”; 小美 . height = 163 ; ``` 重點: **有沒有覺得這樣很麻煩?現在還只是3個學生而已,要填的資料量也不多,如果物件和資料量多一點就會變成枯燥的打字任務,而且程式也會變得又臭又長,可讀性和維護性都會變差。** **那有沒有辦法在物件被建立出來的同時,就把這些資料輸入進去呢?也就是讓物件在被創造出來的同時,就一併完成「初始化」的動作。有的,就是本章要介紹的建構子(constructor)。** 我們加入建構子的觀念,將以上程式碼改寫如下: ```bash= public class Student { String studentID; String gender; int height; public Student(String studentID, String gender, int height) // 定義此類別的建構子 { this . studentID = studentID ; // 在建構子的{ }區塊中定義建構子要做些什麼事 this . gender = gender ; this . height = height ; System.out.println(“我的學號為” + studentID + “,” +“性別為”+ gender + “,” + “身高為”+ height +“公分”); } public int walk() { 此方法的實作程式碼 } public void say() { 此方法的實作程式碼 } } ```  註:以上還用到了「this」變數,讀者可先不理會,待看完「this變數」章節之後就會懂了。 我們在這個類別中多寫了幾列程式碼,用來定義此類別的建構子。於是,我們就可以在從這個類別創造物件時,同時在建構子內輸入引數,這樣被創造出來的物件就會有初始值了,如下: ```bash= // 在創建object時,就創好初始值了 Student 小明 = new Student(“L25247845”,“男”,175); Student 阿華 = new Student(“L25267120”,”男”,182); Student 小美 = new Student(“L29627832”,”女”,163); ``` 並且這個建構子還包含一個println()方法,會在螢幕上顯示出該物件的學號、性別和身高。 懂得建構子的觀念後,我們再來回顧上一段程式碼,也就是在還沒定義建構子的那時候,當我們要創造物件時,語法是這樣寫的: Student 小明 = new Student(); Student 阿華 = new Student(); Student 小美 = new Student(); 等號左側代表我們宣告建立一個Student資料型態(類別)的物件小明、阿華和小美,而等號右側的Student()是這個類別的建構子(constructor)。而因為此時我們沒有定義建構子的內容,所以建構子的()內都不寫東西,代表我們只是創造了一個物件,但這個物件裡面的屬性都是空白的,故後續才需要一個一個指定,但這樣不是好的寫法。  註:像這種情況,即使我們沒有定義建構子的內容,JAVA/C++還是會自動「塞」一個建構子到class中,只是你看不見而已,術語叫做「預設建構子」,所以我們還是可以在以new創造物件時呼叫建構子,只不過這時候就不能在建構子的()內填入引數,因為預設建構子是無引數的建構子。 如果我們在class內就先定義好建構子,並於「new」的時候同時在建構子內輸入引數,就能在創造物件時(new關鍵字),同時把初始值賦予給這個物件的屬性(成員變數)。 由於絕大部分的物件導向程式,起手式都是從定義class開始,並從這個class創造物件,讓物件使用「方法」(method)與其他物件互動,所以學會和徹底了解建構子是非常基本且重要的。 有的人或書籍會說建構子是一種特殊的方法(特殊的成員函數),但這麼說並不太對,因為以下三點是建構子(constructor)和方法(method)的不同之處: 1. 定義建構子時不像函數一樣要先宣告回傳值的型態,建構子是「不可以」宣告回傳值型態的,即使寫void也不行。 2. JAVA強制規定該類別的建構子(constructor)的名稱,一定要和該類別(class)的名稱同名。 3. 建構子的權限一定要設為public。 因為以上三點差異,所以建構子和方法並不完全相同。話雖這麼說,但其實也不用特別去爭論建構子到底是不是一種特殊的方法,這只是認定的問題,我們學會怎麼用就好了。 ----------------------------------------------------------------------------------------- 建構子的(引數)多載: 我們知道方法(成員函數)可以多載(overload),也就是方法會依照我們給它輸入不同型態、不同個數,甚至不同順序的引數,自動去配對所對應的定義去執行。 同樣的,建構子的引數也可以多載,我們可以在定義建構子的時候就做多個定義,讓建構子在偵測到不同型態、不同個數,甚至不同順序的引數時,自動去尋找對應的定義,對new出來的物件做初始化。 JAVA為了方便我們寫程式,如果只是建構子引數的數量不同,就不用分別寫出它們對應的定義,讓我們節省很多時間。例如以下程式,我們定義了3個引數的建構子,但在以new關鍵字對類別做實體化時,在建構子中各輸入3個、2個、1個引數,甚至無引數都行,還是可以創造出四個狗物件,相當方便。 建構子的(引數)多載(overload),範例的程式碼如下: public class Dog { // 定義一個Dog類別 String type ; // 宣告字串型態的type String color ; // 宣告字串型態的毛色 int age ; // 宣告整數型態的年齡 public Dog(String type, String color, int age){ // 定義建構子 this.type = type; this.color = color; this.age = age; } public static void main(String[ ] args){ // 程式的進入點 Dog dog1 = new Dog(”黃金獵犬”、”金毛”、7); // 建構子的多載 Dog dog2 = new Dog(”台灣土狗”、”黑毛”); Dog dog3 = new Dog(”米格魯”); Dog dog4 = new Dog(); } }