CHAPTER 9 建構方法 ROBERT
本章重點 9 - 1 建構方法 (Constructor) 9 - 2 封裝與資訊隱藏 9 - 3 static 共享成員變數 9 - 4 綜合演練
前言 以前一章範例程式中的汽車類別為例, 每次建立物件後, 都還要在 main() 方法中另行設定物件的成員變數的(初始)值: void setCar(double g, double e) { gas = g; eff = e; } oldcar.setCar(100, 10);
前言 如果可以將建立物件與設定物件狀態的動作結合在一起, 會有以下優點: 避免忘記設定物件初始狀態, 這種錯誤看起來雖然是小事, 但往往在程式出錯時也最容易忽略。由於編譯器無法猜測物件在產生後是否需要進行任何初始化的動作, 因此無法像是警告您變數尚未設定初值的方式提出警示。 更接近自然界的物件。舉例來說, 小嬰孩必定在出生前就決定了膚色與髮色, 而不會是先出生, 然後才顯現膚色或是髮色。既然如此, 程式中的各個物件也應該在產生的同時就設定好初始狀態, 直接參與程式的執行。 為了解決上述的問題, Java 這一類物件導向的程式語言便提供一個特別的機制, 來幫物件設定初始狀態, 而這也就是本章的主題。
9 - 1 建構方法 (Constructor) 建構方法就是物件導向程式語言對於物件初始化的解決方案。顧名思義, 建構方法是一個方法 (method), 比較特別的是:它是在建立物件時由系統自動呼叫, 以建構物件初始的狀態, 因此名之為建構方法。也因為在物件產生時會自動呼叫建構方法, 因此使用 new 運算子時, 才必須在類別的名稱之後加上一對小括號, 這對小括號的意義就是呼叫建構方法。
建構方法與一般方法的比較 目的/功能: 類別(class)中定義之注意事項 建構方法 設定物件(屬性/成員變數)之初始值 建構方法名稱必須與類別名稱一樣 沒有傳回值型態,連void也沒有! 預設的建構方法==空的建構方法 (若有定義建構方法,則必須自行定義預設建構方法) 帶參數的建構方法,規則如一般方法 主程式中使用方法: 無參數: TEST a = new TEST(); 有參數: TEST a = new TEST(1, 2, 3); 在建構方法中要呼叫其他同名的建構方法 ,不可直呼其名,必須用this(…)取代之,且必須放置在方法中的第一行
建構方法 (Constructor) 9-1-1 預設建構方法 (Default Construcor) 9-1-2 自行定義建構方法 無參數的建構方法 具有參數的建構方法 9-1-3 建構方法的多重定義 (Overloading) 9-1-4 this 保留字
9-1-1 預設建構方法 (Default Construcor) 建構方法的名稱與類別名稱相同, 如果類別之中並未定義任何建構方法,則 Java 編譯器會自動幫類別定義一個預設建構方法, 例如:
預設建構方法 (Default Construcor) 在上面這個例子中, Test 類別就沒有定義任何的建構方法, 因此 Java 編譯器便會自動定義一個預設的建構方法, 此時就如同以下的程式:
9-1-2 自行定義建構方法 如果需要對新建立的物件進行任何初始化設定, 那麼就可以自行定義建構方法。定義建構方法時除了要依循一般方法的定義規則外, 還有以下幾點需要注意: 建構方法不能傳回任何值, 因此不需也不能註明傳回值型別, 連 void 也不可加上, 如果加上傳回型別, 反而會造成編譯錯誤。 建構方法一定要和類別同名, 而無法使用其他名稱來為建構方法命名。
無參數的建構方法 試問:若增加 Test b = new Test(); b.x=? b.y=?
具有參數的建構方法 建構方法也可以接受參數, 讓物件的建構時更具彈性。建構方法若能接受參數, 在建立物件時, 就可以透過跟隨在 new 運算子以及類別名稱之後的那一對小括號傳入參數。例如:
試問:若增加 Test b = new Test(40, 30); b.x=? b.y=?
具有參數的建構方法 要特別注意的是, 一旦定義了建構方法之後, 使用 new 運算子產生物件時就必須依據建構方法的定義, 傳入相同數量以及型別的參數, 就像是呼叫一般的方法一樣, 否則編譯時就會產生錯誤, 例如:
具有參數的建構方法 編譯後的錯誤訊息告訴我們, 編譯器找不到僅需要單一個整數的建構方法。
9-1-3 建構方法的多重定義(Overloading) 建構方法也和一般的方法一樣, 可以使用多重定義的方式, 定義多種版本的建構方法, 以便能夠依據不同的場合, 為新產生的物件進行最適當的初始設定。編譯器會依據所傳入參數的個數以及資料型別, 選擇符合的建構方法, 就像是編譯器選擇多重定義的一般方法時一樣。 舉例來說, 底下的類別就同時定義有多個版本的建構方法:
建構方法的多重定義(Overloading)
建構方法的多重定義(Overloading) 有一點需要特別注意:當我們為類別定義需要參數的建構方法時, Java編譯器就不會替我們建立無參數的預設建構方法, 因此這時候最好也自行為類別加上一個不需參數的建構方法。因為當程式產生物件時, 未必每次都需要將物件設定為特定狀態, 此時這個不需參數的建構方法就可以提供一種預設狀態給物件, 撰寫程式時就可以享有一定程度的方便性。 因此, 建議在為類別設計建構方法時, 先定義一個不具參數的建構方法,可以將物件設定為預設的狀態。接著, 再根據不同的情況, 定義特殊的版本。
9-1-4 this 保留字 由於建構方法主要的用途是設定物件的初始狀態, 傳入的參數大多與類別的成員變數相關, 因此在為這些參數命名時通常都會和成員變數相同, 這時就和一般的方法一樣, 參數的名稱會遮蔽掉 (Shadowing) 成員變數。如果需要存取成員時, 就可以使用上一章介紹過的 this 保留字, 以表示目前執行此方法的物件。例如:
this 保留字 除了在參數名稱與成員名稱相同的情況派上用場外, this 保留字還有一個很大的妙用。 如果在建構方法中所需要進行的設定, 有一部份在另外一個版本的建構方法中完全重複, 而想要在直接呼叫該版本的建構方法時, 並不能直接使用類別名稱呼叫該建構方法:
this 保留字 在第 6 行中, 本來想要利用另一個只需單一參數的建構方法設定成員變數 x 的值, 但是從編譯後的錯誤訊息說明了編譯器找不到一個叫做 Test()的方法。換句話說, 雖然建構方法和一般方法很類似, 但在 Java 中卻是被視為不同的元素, 不能以呼叫其它方法的方式呼叫建構方法。因此要呼叫其他版本的建構方法, 必須使用 this 保留字, 例如:
注意:此二行不得調換, 建構方法中呼叫另一同名建構方法this()必須為第一行
this 保留字 第 6 行的敘述, 就是使用 this 呼叫其他版本建構方法的方式, 在 this 之後的小括號可以放入要傳遞給其他版本建構方法的參數, 編譯器就是透過這裡的參數個數與型別來找尋適當的其他版本。 為了類別特性的一致性, 建議您可以多利用 this 保留字, 將重複的設定動作集中在適當的建構方法中, 並且在其他需要同樣建構方式的建構方法中呼叫該建構方法, 避免因為在不同的建構方法中的疏忽, 而使得產生的物件行為或是特性不一致。
9 - 2 封裝與資訊隱藏 學會建構方法的用法後, 即可在建立物件時, 一併完成物件的初始化, 不必再於 main() 方法中直接修改物件的成員變數。但我們現在僅只是『不必』直接存取成員變數, 對物件導向程式設計方法, 則是要求『不能』直接修改物件的成員變數。以術語來說就是資訊隱藏 (Information Hiding), 亦即類別外部 (例如 main() 方法) 不能看到、接觸到物件內部的資訊 (屬性)。
封裝與資訊隱藏 那外部要如何得知或改變物件的屬性呢?那就必須透過類別公開給外部的方法, 對應到生活中實際接觸的物件也是如此, 例如要讓車子前進, 必透過車子提供給外部的油門;要轉彎, 可使用方向盤;而要讓行進中的車子停止, 則要使用剎車。油門、方向盤、剎車就是車子提供給我們操作車子的方法, 使用這些方法, 就會改變車子的狀態與屬性 (速度、方向、位置、油量等等)。
封裝與資訊隱藏 因此設計類別時, 就必須提供必要的方法, 讓外部能正常操作物件; 而透過這種程式設計方式, 只要類別有公開能操作物件的方法,其他人就算完全不知道類別內部是如何設計、運作, 也可透過這些公開的介面來使用我們所設計好的類別, 達到程式碼重複使用、提高軟體開發效率的目的。 就好比大部份的駕駛人不會瞭解車子內部是如何設計與運作, 但只要會使用車子公開的油門、方向盤、剎車. . .等介面, 就會開車。而將類別的屬性、操作屬性的方法包裝在一起, 只對外公開必要的介面, 即稱為封裝(Encapsulation)。
封裝與資訊隱藏 9-2-1 類別成員的存取控制 9-2-2 為成員變數撰寫存取方法 9-2-3 傳回成員物件的資訊
3PFS 3P Private :成員變數不得直接使用 Protected、Public F Final:變數一經設定初始值後,不得再改變 setXXX()、getXXX() Protected、Public F Final:變數一經設定初始值後,不得再改變 S Static:一經宣告即可使用 用於變數:具獨立且共同之記憶體空間 用於方法:不須宣告即可以類別名稱呼叫之 toString() 印中加物件名稱,若有宣告則呼叫toString(),否則為該物件之參照位址 System.out.println(“IOU”+a); System.out.println(“IOU”+a.toString());
9-2-1 類別成員的存取控制 為了讓外部不能任意存取封裝在類別內的屬性或方法, 我們必須在類別之中, 使用存取控制字符 (Access Modifier) 來限制外部對類別成員變數的存取。以下可以使用的存取限制字符:
類別成員的存取控制 其中 protected 存取控制字符會在第 11、13 章做進一步的說明, 本章先說明 private 及 public。private 存取控制字符, 就如其英文字面含意一樣, 是指該成員變數是類別所私有, 除了類別中的方法以外, 對於其他的類別來說,這個成員變數都好像看不到一樣, 無法使用。例如:
類別成員的存取控制
類別成員的存取控制
類別成員的存取控制 存取限制字符也可以應用在方法上, 用來限制哪些方法可以被外界呼叫, 而哪些方法只是提供給類別中的其他方法呼叫。 這正好一開始所提到的資訊隱藏特性, 在上述的例子中, main() 方法不能直接存取物件的成員變數值, 只能透過類別所提供的 show()、modifyMember() 方法來顯示或修改成員變數, 至於怎麼顯示或修改, main() 方法則不需去瞭解。 如果沒有特別標示存取控制字符, Java 就會採用預設控制 (Default Access),也就是只有同一個套件 (Package) 的類別可以存取此成員變數。 套件:目前只需先記得, 如果編譯好的 .class 檔案都位於同一個資料夾, 那麼這些類別就會被視為是在同一個套件中。 同一個檔案中的類別在編譯後都會在同一個資料夾下。 存取限制字符也可以應用在方法上, 用來限制哪些方法可以被外界呼叫, 而哪些方法只是提供給類別中的其他方法呼叫。
9-2-2 為成員變數撰寫存取方法 為了實作資訊隱藏這個物件導向程式設計的基本觀念, 在設計類別時, 就要注意應盡量避免暴露類別內部的實作細節, 讓類別的使用者可不依賴內部實作細節亦可撰寫程式。這樣的好處之一, 即是若日後類別需變更內部的實作方式, 但只要它仍提供相同的操作方法, 則使用者也不必修改使用到該類別的程式。 因此為了隱藏成員變數, 我們就需適時地為成員變數加上存取限制。一般而言, 可使用下列的原則:
為成員變數撰寫存取方法 除非必要, 最好所有成員變數都加上 private 存取限制。 如果使用此類別的程式需要透過成員來完成某件事, 就由類別提供方法來完成。 如果需要修改或取得成員的值, 就提供專門存取成員的方法。 通常用來取得成員值的方法會命名為 getXXX, 其中 XXX 就是成員變數的名稱;相對的, 用來設定成員值的方法就稱為setXXX。這樣一來, 可以將更改成員的動作侷限在此方法中, 往後對於除錯或要為更改成員而引發的影響加上處理工作時就會比較方便。
為成員變數撰寫存取方法 相同的道理, 對於類別中所定義的方法, 加上存取限制的通則如下: 如果是要提供給外界呼叫的方法, 請明確的標示為 public 存取限制。像是剛剛所提到的 get、set 方法, 就是最好的例子。 如果只是供類別中其他的方法呼叫的方法, 請明確的標示為 private 存取限制, 以避免被類別外部的程式呼叫。
為成員變數撰寫存取方法 對於建構方法, 除非有特別的用途, 否則應該都標示為 public, 因為若是標示為 private, 則 new 運算子就無法呼叫建構方法, 而不能設定物件的初始狀態了。 以下面的程式為例:
為成員變數撰寫存取方法
為成員變數撰寫存取方法
為成員變數撰寫存取方法 在程式中第 10〜13 行就為 Test 類別的 private 的成員 x、y 提供了一組存取的方法, 並分別取名為 getX、setX 與 getY、setY, 同時也特別將這2組存取方法都標示為 public 存取限制。 回頭看前一章的汽車類別範例, 只要加上合適的建構方法, 並將成員變數設為 private, 就可讓它將資訊隱藏起來, 我們只能透過它所公開的方法來控制物件:
為成員變數撰寫存取方法
為成員變數撰寫存取方法
為成員變數撰寫存取方法
為成員變數撰寫存取方法 以這種方式撰寫程式時, main() 方法的內容看起來會比較簡捷, 因為其中大多是直接呼叫類別所提供的方法, 我們也比較能看出 main() 方法是在做什麼事。
9-2-3 傳回成員物件的資訊 透過前幾個例子, 對資訊隱藏有初步的認識, 原則就是將成員變數設為 private, 並提供必要的公開方法。 但如果類別的成員變數是另一個類別的物件, 則在設計與此成員物件相關的公開方法時, 要注意是否要將這個私有成員物件, 也公開到外部。 舉例來說, 在平面幾何中, 一個圓的可以由一個圓心座標和半徑來定義。因此我們可以先設計一個代表座標點的類別 Point, 然後再於圓的類別中用Point 的物件代表圓心座標, 例如:
傳回成員物件的資訊
傳回成員物件的資訊 在 Circle 類別中的 getP() 方法, 其用途是讓外界取得圓心座標, 但如果直接傳回私有成員變數 p 的參照, 那麼外界就可取得此物件的參照, 並透過此參照呼叫 Point 類別的 setx()、 sety() 方法, 如此一來就變成外界可直接修改私有成員物件了, 請參考以下的例子:
成員變數區 一般方法區 建構方法區
答案印出 圓心:( 6, 4 ) 半徑 :5
6 3 p x c 4 y 5 r Circle c=new Circle(3,4,5) c.getp() Point p =c.getp(); p p.setx(6); 6 答案印出 圓心:( 6.0, 4.0 ) 半徑 :5.0
傳回成員物件的資訊 在第 30 行為 Circle 類別定義了一個取得圓心座標的 getp() 方法, 此方法直接將成員變數 p 傳回, 也就是傳回圓心物件的參照。因此當 main() 方法在第 52 行用 getp() 方法取得圓心後, 可在第 53 行用它呼叫 Point 類別的 setx() 方法來變更 X 軸座標。由執行結果也可看到圓心的 X 軸座標的確被更改了。
傳回成員物件的資訊 雖然這樣改變圓心座標的方式看似合理, 但對 Circle 類別而言, 卻失去『資訊隱藏』的特性, 因為外界不需透過它, 即可任意變更其圓心座標。雖然成員變數 p 確實是 private, 但因為 getp() 方法是將其參照傳回, 所以外界即可透過此參照直接存取到私有的物件。 如果要保護 Circle 類別的內容, 則可修改 getp() 方法, 讓它變成傳回另一個座標值相同的 Point 物件, 而非傳回私有的 Point 物件參照, 如此一來外界仍能取得一個代表圓心座標的 Point 物件, 但該物件並非 Circle 類別的成員, 因而可達到『資訊隱藏』的目的。修改後的程式如下:
注意比較
6 3 p x c 4 y 5 r Circle c=new Circle(3,4,5) c.getp() 3 p x Point p =c.getp(); 4 y p p.setx(6); 6 答案印出 圓心:( 3.0, 4.0 ) 半徑 :5.0
傳回成員物件的資訊 這個範例與前一個範例有 2 個主要不同之處: 第 25 〜28 行為 Point 類別定義了另一個建建構方法, 此建構方法是用現有的點物件為參數, 並複製參數物件的座標值給新物件。 第 35〜37 行的 getp() 方法, 改成傳回一個新建立的 Point 物件, 而非私有的成員變數 p, 但建立新物件時則是以 p 為參數, 所以傳回的物件之座標會與圓心相同。
傳回成員物件的資訊 經過上述的修改後, 第 57、58 行取得並修改圓心的座標時, 即不會動到Circle 物件實際的圓心。由執行結果可發現, 程式第 59 行顯示圓的資訊時, 其圓心座標並未被修改。 這兩個範例程式中, 都為類別定義了一個 toString()方法, 這個方法會將物件的資訊以字串的形式傳回, 這種設計方式, 讓我們需要輸出物件資訊時, 可以有較彈性的用法, 因為我們可利用 "+" 運算子將多個字串組合在一起。 return 之後 的寫法規則如同System.out.print()的括號中的寫法規則相同 returen ….. ; System.out.print(…..) ;
9-3 static 共享成員變數 前面的類別範例所建立的物件, 都能擁有個自己成員變數, 以表現物件屬性間的差異。但在某些情況下, 我們可能會想讓所有物件的某個屬性都是相同的, 此時就可使用 static 共享成員變數來表現這個物件的共通屬性。 以我們示範過的汽車類別為例, 假如該類別代表的是某一款特定的車型,所有物件代表同型車的多個個體。
static 共享成員變數 載油量當然會隨車子所加的油量、行駛的里程而隨時變動;但耗油率我們可能想將之設為固定值, 即所有物件的耗油率都相同。此時若單只是在建構物件時, 將耗油率設為相同的數值, 並不方便, 也不安全, 因為如果寫程式時不小心寫錯了, 就會造成耗油率不一致等問題。 因此 Java 就提供 static 的成員變數, 來解決這個問題。
static 共享成員變數 9-3-1 static 存取控制 9-3-2 使用類別名稱存取 static 成員變數 解開main() 方法之謎 9 - 3 -5 final 存取控制
9-3-1 static 存取控制 當我們將類別的成員變數加上 static 存取控制字符, 就表示所有屬於此類別的物件, 都會共享這個成員, 而非每一個物件擁有自己的一份成員。舉例來說:
static 存取控制
static 存取控制 在程式 18 〜20 行雖然分別為物件的成員變數 y 設定不同的值, 但由於該成員變數為 static , 所以其實這 3 個物件的成員變數 y 是同一份, 每次設定值時, 都是設定同一個 y, 因此最後一次呼叫建構方法時將之設為 60 之後, 不論是透過 a、b、c 參照來取得成員變數 y 的值, 都是60 了。反之, 成員變數 x 則因為不是 static, 所以個別物件都享有自己的一份。
9-3-2 使用類別名稱 - 存取 static成員變數 stat ic 成員變數除了可用如同一般成員變數的方式存取外, 也可以透過類別名稱存取之。以剛剛的 Test 類別, 我們可以用如下的方式存取成員變數 y:
使用類別名稱存取 static成員變數
使用類別名稱存取 static成員變數 在第 21 行以『類別名稱.成員變數名稱』的方式即存取到 y, 並將它設為 100, 所以之後顯示物件內容時, 其 y 值都是 100。 此外, 我們甚至可在未建立物件的情況下, 也能使用類別的 static 成員變數:
使用類別名稱存取 static成員變數 注意:還沒new()
使用類別名稱存取 static成員變數
使用類別名稱存取 static成員變數 在這個範例中, Test 類別的建構方法只會設定成員變數 x 的值, 而第 17行則在未產生任何物件之前即存取 static 成員變數 y, 並設妥其值, 所以之後的建構方法雖未設定 y 的值, 但由執行結果可看到各物件的 y 值都是 100 。
9-3-3 static 初始區塊 由於 static 成員變數的共享特性, 通常不會在建構方法中設定其初值, 因此 static 成員變數要不就是在(1)宣告的同時直接設定初值, 要不就是(2)另外單獨設定。 為了避免寫程式時忘了設定 static 成員變數, Java 還提供了 static 初始區塊 (Static Initializer), 可以確保在產生物件之前, 設定 static 成員。其用法就是在類別的定義中, 加入一個以 static 保留字為首的大括號區塊, 並在此區塊中加入初始化 static 成員變數的敘述。例如:
stat ic 初始區塊
static 初始區塊
static 初始區塊 在類別中的 static 區塊, 會在程式使用到該類別之前執行。以上列程式為例, 第 5〜 7 行就是 static 初始區塊, 它會在程式中第一次使用到 Test 類別 (即第 23 行) 之前執行, 因此第 23 行顯示的結果就是執行過 static 初始區塊後的成員 y 的值100。
static 初始區塊 由於 static 成員變數是由同一類別的所有物件所共享, 且不需先產生物件, 即可以透過類別名稱存取, 因此又稱為類別變數 (Class Variable);相對的, 非 static 的成員變數因為是每個物件各自擁有一份, 需建立物件後才能使用, 因此稱為實體變數 (Instance Variable)。
9-3-4 static 方法 static 除了可以使用在成員變數上以外, 也可以應用在方法上。一個標示有 static 存取控制的方法除了可以透過所屬類別的物件呼叫以外, 也和 static成員變數一樣, 可以在沒有產生任何物件的情況下透過類別名稱呼叫。例如:
static 方法
static 方法 由於 static 成員變數及方法不需產生物件即可使用的特性, 因此可以用來提供一組相關聯的工具方法或是常數值, 像是 Java 類別庫中的 Math 類別,就提供許多與數學相關的 static 運算方法 (像是算次方、取亂數、三角函數等等) 以及常數值 (例如圓周率)。
static 方法 請特別注意, 在 static 區塊或方法之中, 不能用到任何非 static 的成員變數以及方法, 也不能使用 this 保留字。這其實很容易理解, 因為非 static 的成員變數和方法是跟隨物件而生, 而 static 區塊或是方法可以在沒有產生任何物件之前使用, 此時因為沒有產生物件, 自然就不會配置有非 static 的成員變數, 而 this 也沒有物件可指。
解開main() 方法之謎 從這裡的解說就可以將 main() 方法的神秘面紗揭開了, 原來 main() 方法只是一個 public static 的方法, 而且不會傳回任何值。
9 - 3 - 5 final 存取控制 static 成員變數常常用來提供給同一類別的所有物件一份一致的資料, 供所有的物件共用。(全域變數) 為達成此目的, 還需要有一種方法, 可以在設定好 static 成員變數的初值後就不能更改, 否則各別物件都隨意去更動 static 成員變數的值, 就不是一份一致的資料了。 為達到此目的, 可以搭配第 3 章介紹過的 final 字符, 限制特定的 static 成員變數在設定過初值之後就不允許更動, 例如:
final 存取控制
final 存取控制 第 2 行中宣告了 x 是 final, 所以第 9 行的設定動作在編譯時就會被視為錯誤。 要特別注意的是, 一旦宣告了成員變數為 final 後, 如果是 static 成員變數, 那麼就必須要在宣告同時或是在 static 初始區塊中設定初值;如果是非 static 成員變數, 就必須在宣告同時或是在建構方法中設定初值, 否則都會被視為是錯誤。
9 - 4 綜合演練 9 - 4 - 1 提供輔助工具的類別 9 - 4 - 2 善用多重定義
9 - 4 - 1 提供輔助工具的類別 在 Java 中, 通常會使用 static 方法提供輔助工具給其他類別使用。舉例來說, 我們可以提供一個負責找出最大值與最小值的類別, 以方便所有需要在陣列中尋找極值的場合。
提供輔助工具的類別
提供輔助工具的類別
提供輔助工具的類別 在這個程式中, Utility 類別的功能就是提供了 2 個方法, 個別可以在陣列中找出最小及最大值。只要遇到需要找尋極值的時機, 都可以直接使用這 2個方法, 完全不需要產生物件。這其實也是 Java 提供許多公用程式的作法, 我們會在第 17 章介紹 Java 標準類別庫。
9 - 4 - 2 善用多重定義 在定義類別時, 建議您為類別提供一個最富彈性的建構方法, 可以完全設定各個成員變數的值, 然後連同不需參數的建構方法在內, 都呼叫此建構方法來進行設定工作。舉例來說, 如果要撰寫一個代表矩形的類別, 就可以這樣做:
善用多重定義
善用多重定義
善用多重定義
善用多重定義 第 14 ~ 17 行就是最富彈性的建構方法, 其他的建構方法都呼叫它來完成建構的動作。透過這樣的設計方式, 在新增建構方法時, 就可以很方便的完成工作, 而不需要自行處理個別成員變數的設定動作。