7-3 物件的產生
7-3-1 物件產生敘述 – new() 設計好類別藍圖之後,接下來必須考慮如何將類別實現成為一個可執行運作的『物件』。像是蓋房子一樣,同一張建築藍圖可能因所需的人不同、所蓋的地理位不同、所建設的時間不同…等等不同因素,即使照圖蓋出外觀一樣的房子,內裝樣式卻可能出現很大的差別。由此可見,由同一份類別所產生的物件之間,也會因所面臨的狀況不同,產生外觀相同,內部大異其趣的物件。因此,任一時機內,由類別產生一個物件,只不過當時狀況的一個『驗例』(Instance)而已,由類別產生物件的過程稱為『驗例化』(Instantiate,某些地方稱為物件化)。利用 new () 函數呼叫,由類別產生一個物件,語法如下:
重點說明如下: (1) class_name object_name(如 Employee Liu):宣告某一資料型態為 class_name 類別(如 Employee)的物件,其名稱為 object_name(如Liu)。其實宣告類別的語法,與宣告基本資料型態變數的方法很類似,如 int k 語句。 (2) object_name = new class_name()(如 Liu = new Employee()):產生一個 class_name 型態(如 Employee)的物件,並填入 Liu 物件內。像是整數宣告int k = 10 。 (3) 上述兩個敘述可整合一個敘述達成,則為 class_name object1 = new class_name(),譬如 Employee Cheng = new Employee ()。 上述範例中,Employee 為事先製作好的類別,並經過編譯成 Employee.class(Bytecode,中介程式);而且須與原程式儲存放於同一目錄底下,否則必須利用 classpath 變數(第一章有設定 classpath 說明),標明 Employee.class 的所在位置。利用 new 產生的物件其特性如下: (1) 變數成員表示:經由類別產生的物件,該物件內的變數成員也繼承了原類別所規劃的屬性,可能是 public、private 與 protected 的存取限制。變數成員的表示方法為: 『object_name.variable_name』(如 Cheng.name) (2) 方法成員表示:物件內的方法成員承襲了原類別所規劃的屬性,可能是 public 或 private;方法成員表示為: 『object_name.method_name』(如 Cheng.setID()) 7-3-2 範例研討:規劃通用型人事資料 (A)程式功能:Ex7_1.java、Employee.java 展鵬網路行銷公司需要一套較完整的人事資訊系統,該系統允許編輯員工資料,每一員工的描述屬性有: (1) 員工代號(ID):整數。必須高於 1000,且低於 5000。 (2) 姓名(name):字串。 (3) 部門(depart):字串。 (4) 底薪(payment):整數。必須高於最低薪資 15800 元。 (5) 加班時數(extra):整數。最高 45 小時。 請先建立一只雛型程式,允許輸入員工資料,如輸入資料不符規定,則不予輸入並顯示錯誤原因。輸入完畢後印出該員工的薪資表,其中加班費計算方式為每小時 = (底薪 / (30 * 8)) * 1.5。期望操作介面如下: (1) 編譯後,正常執行如下:
(2) 如果員工編號不在 1000~5000 範圍內,系統會拒絕操作並離開,如下:
(3) 如果員工薪資低於 15800,則系統會拒絕操作並離開,如下:
(4) 如果員工加班時數超過 45 小時,則系統會拒絕操作並離開,如下:
物件的簡單應用,如同傳統語言的『結構變數』一樣,大多運用於描述環境的事實現象(或稱 Entity)。但物件不僅被動的描述 Entity 的屬性外,如果給予適當的處理,它可主動判斷『事項』是否已超過真實現象。以電子化人事系統為例,對於公司內員工薪資或工時計算大多不可以違反『勞工法』規定,譬如員工代號大多有一定格式、勞工最低薪資、每月最高超工時數、等等。 我們相信公司裡某些規定是適合所有員工,也就是員工資料制定完成之後,大多可以適用所有部門員工。因此,吾人依照展鵬公司的需求,製作了如圖 7-5 的 Employee 類別(Employee.java),其他應用系統也可直接引用,如此則可以整合公司內的員工資料。圖 7-5 是由 Employee 類別產生 worker 與 sales 員工物件的範例。設計完成員工資料類別之後,再編寫建立員工資料程式(Ex7_1.java)就不會困難了。
圖 7-5 員工資料的物件範例 吾人利用 Employee.java 建構宣告員工物件的類別(Employee.class);該類別內包含 5 個變數成員(其中 3 個是隱藏式變數),與 6 個存取隱藏變數的方法成員,然而它們即是該類別的輸入/輸出埠口。從外觀來看,Employee.class 抽象功能如圖 7-6 所示。各項功能如下說明: (1) 屬於輸入埠口: (a) int setID(int i):設定員工代號,如 i 介於 1000~5000 之間則執行正常返回 1;否則返回 0。該方法是設定物件內變數成員,屬於輸入埠口之一。 (b) int setPayment(int pay):設定員工底薪,如 pay 大於 15800,則執行正常並回傳 1;否則回傳 0,表示拒絕操作。屬於物件的輸入埠口之一。 (c) int setExtra(int ex):設定員工加班時數,如 ex 小於 45 則執行正常並回傳 1;否則回傳 0。屬輸入埠口之一。
圖 7-6 Employee.class 類別架構 (2) 屬於輸出埠口: (a) int getID():取得員工代號。輸出埠口之一。 (b) int getPayment():取得員工底薪。輸出埠口之一。 (c) int getExtra():取得員工加班時數。輸出埠口之一。 (d) name:儲存員工姓名的變數,可任意存取。 (e) depart:儲存服務部門的變數,可任意存取。 (3) 屬於物件變數: (a) 公開變數:有 name(員工姓名) 與 depart(服務部門)等 2 個變數,外部程式可以直接存取(讀或寫)。 (b) 私有變數:有 ID(員工編號)、payment(底薪) 與 extra(加班時數) 等 3 個變數,外部程式不可以直接存取,必須透過輸入/輸出埠口存取,如 setID()、getID()、、、等物件方法。 (4) Employee.java 程式範例,如下
圖 7-7 Employee.java 程式架構
程式重點說明: (1) 第 6~10 行:宣告類別的變數成員,並指定其相關屬性(如 private)。 (2) 第 14~23 行:『int setID(int i) { ..}』。宣告 setID() 方法成員,該方法被呼叫時,會攜帶參數 i,如果該參數介於 1000 與 5000 之間,則這定員工代號,並回傳一個整數 1;否則拒絕設定,亦回傳 0。 (3) 第 24~26 行:『int getID() {…}』。宣告 getID() 方法成員,功能是回傳員工代號(ID)。 (4) 第 27~37 行:『int setPayment(int pay) { ..}』。功能是設定員工底薪的方法成員;當引數(pay)底薪低於 15800 元,該方法會拒絕輸入,並回傳一個整數 0;否則回傳整數 1。 (5) 第 38~40 行:『int getPayment() {…}』。 讀取員工底薪的方法成員。 (6) 第 41~50 行:『int setExtra(int ex) { ..}』。輸入員工加班時數的方法成員;當引數超過 45 時,會拒絕輸入並回傳 0;否則回傳 1。 (7) 第 51~53 行:『int getExtra() { … }』。讀取員工加班時數的方法成員。
圖 7-8 Ex7_1.java 程式架構 製作完成 Employee 類別之後,吾人再編寫一主程式,引用該類別來產生工作員(worker)。針對 worker 物件輸入與輸出資料,證實 Employee 類別所提供的方法與變數成員是否能滿足所需。
程式重點說明: (1) Employee.class 需存在於相同目錄下。 (2) 第 9 行:『Employee worker = new Employee();』。利用 Employee 類別產生 worker 物件,則該物件擁有原類別所宣告的方法與變數成員。 (3) 第 14 行:『worker.name = keyin.readLine();』。Worker.name 變數成員屬於公開性的(非隱藏性),可以直接存取。 (4) 第 21~24 行:『if (worker.setID(id)==0) { ..}』。呼叫 worker 物件的 setID() 方法成員,表示透過 setID() 將引數 id 值寫入 ID 變數內。執行後回傳是 0 的話,表示執行不正確。因 worker.ID 是隱藏性變數,無法直接存取,必須透過其他方法成員才行。 無人稍修改 Ex7_1.java 程式,測試直接存取 worker.ID、worker.extra 與 worker.payment 等隱藏性變數。修改部分程式內容:Ex7_1_1.java
其編譯結果如下:
|
翻轉工作室:粘添壽
Java 程式設計(二) 含物件導向
翻轉電子書系列:
|