Presentation is loading. Please wait.

Presentation is loading. Please wait.

物件導向程式設計 參考書目: 1. 洪維恩,C++ 教學手冊 第三版,旗標出版圖書公司。 2. 陳錦揮,Java 初學指引,博碩文化 3

Similar presentations


Presentation on theme: "物件導向程式設計 參考書目: 1. 洪維恩,C++ 教學手冊 第三版,旗標出版圖書公司。 2. 陳錦揮,Java 初學指引,博碩文化 3"— Presentation transcript:

1 物件導向程式設計 參考書目: 1. 洪維恩,C++ 教學手冊 第三版,旗標出版圖書公司。 2. 陳錦揮,Java 初學指引,博碩文化 3
物件導向程式設計 參考書目: 1. 洪維恩,C++ 教學手冊 第三版,旗標出版圖書公司。 2. 陳錦揮,Java 初學指引,博碩文化 3. 施威銘研究室著,最新 Java 2 程式語言 第 2 版,旗標出版社。 Java類別與物件 Chih-Hung Wang

2 Java的類別 語法說明: (1)類別定義的第一行,我們可以視為類別的宣告。當中所有 的[]都可以不存在。因此我們暫不討論(後面會陸續介紹)
而其中類別的[封裝等級],只有public或不出現兩種,當出現public時 ,代表該類別為主類別,而主類別必須與檔名取相同的名稱。 同時,只有被宣告為public的類別才能被import進來。在本章中,我 們宣告類別時,都不會出現該欄位(除主類別外)。 (2)在類別中定義的資料與函式,分別稱為fields與methods。關 於fileds及methods的翻譯與物件導向設計的對照請見下表。

3 Java的類別 (3)類別中可以對成員變數及成員函式定義多種『封裝等級』 如下,在本章中,我們將先說明『公用等級』及『私用等級』 ,而『保護性等級』則留待繼承一章中再做說明。如果省略宣 告成員的封裝等級,則該成員只能被同一個Package的類別存 取,而無法被不同Package的類別存取,此稱為package封裝等 級(詳見第11章)。 Java原始說明文件 物件導向設計 C++ 本書翻譯 其他 field 屬性(Property) 成員變數 資料欄位、成員變數、成員資料、屬性 有時不翻譯 method 方法(Method) 成員函式 函式、成員函式、方法

4 Java的類別 public:公用等級資料型態 private:私用等級資料型態 protected:保護性等級資料型態 空白:package等級 (4)在類別中,『不同的存取等級』代表『不同的資料保護方 式』,資料之所以需要保護,最主要的目的是為了讓各類別的 資料獨立開來,且不易被其他不相干的函式所修改,達到物件 導向程式設計中,資料封裝及資料隱藏的功能。 (5)根據上述定義類別的語法,我們可以利用下圖來示意類別 的內部結構:(以下省略了package等級)

5 Java的類別 (6)私用等級資料只能被同一個類別的成員函式存取;而公用 等級的資料則除了類別內的成員可以存取之外,其他外部的函 式也都可以存取宣告為公用等級的資料。 資料等級(省略package等級)

6 Java的類別 【範例1】 (7)宣告資料成員與定義成員函式的順序可以交錯
(8)成員變數可以設定初值且該初值會在物件實體產生時,自 動被設定。 (9)類別的命名在第二章曾經提過,本書所採用的習慣為第一 個字母大寫(通常命為C,代表class),其後由一個單字以上 組成,每個單字的開頭字母為大寫,其餘為小寫 例如:CPerson,CStack,CCircularQueue。 【範例1】 定義一個CStudent類別,將其成績、地址、電話宣告為『私用 等級資料型態』;學號、姓名、科系宣告為『公用等級資料型 態』。

7 Java的類別 或 class CStudent { private float score;
private String address; private int phone; public int id; public String name; public String major; } class CStudent { private float score; public int id; //相同封裝等級的不一定要擠在一起 private int phone; public String name; private String address; public String major; }

8 Java的類別 【範例2】 延續範例1,在CStudent類別中,宣告兩個『公用等級』的( 成員)函式,分別為showId( )和showMajor( ),函式用途分別 為『顯示學號』及『顯示科系』。 class CStudent { private float score; private String address; private int phone; public int id; public String name; public String major; public int showId( ){...} //顯示並回傳學號,回傳型態為int public void showMajor( ){...} //顯示科系,回傳型態為void }

9 Java的類別 範例說明: 上述範例,當物件被實際建立之後,id,name,major都可以被外部函式 所取用,showId()與showMajor()也可以被外部程式所執行,但score、 address與phone只能被同一類別的成員函式存取(例如showId成員函 式)。 class CStudent { private float score; private String address; private int phone; public int showId( ){...} //顯示並回傳學號,回傳型態為int public void showMajor( ){...} //顯示科系,回傳型態為void public int id; public String name; public String major; }

10 Java的物件 類別是許多資料變數及函式合成的結構型資料型態,和 陣列很相似。當我們想要使用類別時,必須透過宣告變 數與產生實體才能夠使用(除了被宣告為static的變數與 方法外)。 而由類別宣告的變數,稱之為物件參考或物件變數。而產生的 實體則稱為物件實體(instance)。 對照圖7-1,我們可以將Java的類別與物件重新描述如下 圖:

11 Java的物件 Java類別與物件關係圖 (請與圖7-1對照比較)

12 Java的物件 宣告物件變數與產生物件實體
宣告物件變數與宣告一般變數差不多,只不過是把原始資料型態改為 類別名稱,語法如下: 類別宣告物件變數語法 語法說明: 上述語法可以出現在任何類別內,也可以出現在任何 method內。當宣告物件變數後,由於物件變數是一個參 考,故開始時並未指向任何實體,此時的內容會被初始 化為null。 【範例】:宣告一個CStudent類別的物件變數,名稱為John。 類別名稱 物件變數名稱;

13 Java的物件 宣告物件變數與產生物件實體 【範例】:宣告一個String類別的物件變數,物件名稱為str1。
【說明】String類別已經被定義於java.lang Package,故載入該類 別即可。 class CStudent { ……類別定義…… } CStudent John; //宣告物件變數John,本敘述應出現在類別或方法內 import java.lang.String; String str1; //宣告String物件變數str1,本敘述應出現在類別或方法內

14 Java的物件 宣告物件變數與產生物件實體 產生物件實體 產生物件實體使用的是new運算子,語法如下: 產生物件實體語法 語法說明:
這個語法由於不屬於變數宣告,故只能出現在method內。上述語法除了可 以產生物件實體,並將實體的參考設定給物件變數之外,還可以透過引數 串列呼叫特定的建構子。建構子(Constructor)是一個特殊的函式,可以在 物件實體產生時,進行一些初始化動作。如果不需要傳遞引數,則可以省 略引數串列。 【範例】:為CStudent類別的物件變數John產生一個實體。 John = new CStudent(); 物件變數 = new 類別名稱(引數1,引數2…);

15 Java的物件 宣告物件變數與產生物件實體 【範例】:為String物件變數str1產生一個實體並設定其初始值 為"Hello"。 【說明】
str1 = new String("Hello"); 【說明】 String類別不是我們所開發的類別,其建構子(Constructor)已經由JDK 完成,在Java說明文件中,可以查詢Constructor Summary文件段,會 發現許多與類別同名的函式,這些函式就是建構子。

16 Java的物件 宣告物件變數與產生物件實體
宣告物件變數並產生實體 我們可以於宣告物件變數時,同時產生物件實體,語法如下: 語法說明: 上述語法只是將之前的兩個語法合併。上述語法可以出 現在任何類別內,也可以出現在任何method內。 【範例】:宣告CStudent類別的物件變數John,並產生一個實體,使 John指向該實體。 CStudent John = new CStudent(); 【範例】:宣告String物件變數str1,並產生一個實體,實體內容初始 化為"Hello",並使str1指向該實體。 String str1 = new String("Hello"); 類別名稱 物件變數名稱 = new 類別名稱(引數1,引數2…);

17 Java的物件 存取成員變數與執行成員函式
當物件實體被產生以後,我們就可以合法存取公用等級資料變 數以及執行公用等級的成員函式(如果敘述處於同一類別則不 限封裝等級皆可存取),而且存取方法很簡單,只要在物件與 欲取用資料之間加上『.』運算子即可,如下語法: 存取成員資料與執行成員函式語法: 物件.成員資料 物件.成員函式(引數1,引數2,…)

18 Java的物件 存取成員變數與執行成員函式
語法說明: (1)私用資料與函式,只能被同一類別內的成員函式存取與呼叫。(至於保 護資料與函式則留待繼承一章再作說明) (2)上述語法是外部程式的存取與呼叫語法。如果是同一類別內的存取與呼 叫,則不需要指定物件,因為當它被執行時,它已經是物件本身。 【範例1】將John物件的id變數設定為 ,設定John物件 的name變數為"John"。 John.id = ; John.name="John"; 【範例2】透過showMajor()成員函式顯示John的科系名稱。 John.showMajor();

19 Java的物件 存取成員變數與執行成員函式 【錯誤範例】私用資料與函式,只能被類別內的成員函式存取 ,所以下列是錯誤的敘述:
【觀念範例7-1】:定義類別、宣告物件並存取物件的公用成 員資料。 範例7-1:ch7_01.java(隨書光碟 myJava\ch07\ch7_01.java) public class 主類別名稱 { static CStudent John; public static void main(String args[]) John = new CStudent(); John.score = 85.5; //錯誤,因為score是私用資料 John.address="台北市大安區"; //錯誤,因為address是私用資料 }

20 Java的物件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 /* 檔名:ch7_01.java 功能:定義汽車類別與宣告3個物件 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CCar bus = new CCar(); CCar truck = new CCar(); CCar taxi = new CCar(); bus.name="公車"; bus.wheel=6; bus.person=40; truck.name="卡車"; truck.wheel=8; truck.person=3; taxi.name="計程車"; taxi.wheel=4;

21 Java的物件 執行結果: 公車有6個輪子,可載40人 卡車有8個輪子,可載3人 計程車有4個輪子,可載5人 26 27 28 29 30
31 32 33 34 35 36 37 38 39 40 41 42 43 44 taxi.person=5; //taxi.engine="V16"; //不可存取私用等級的變數 System.out.print(bus.name + "有" + bus.wheel + "個輪子"); System.out.println(",可載" + bus.person + "人"); System.out.print(truck.name + "有" + truck.wheel + "個輪子"); System.out.println(",可載" + truck.person + "人"); System.out.print(taxi.name + "有" + taxi.wheel + "個輪子"); System.out.println(",可載" + taxi.person + "人"); } class CCar { public int wheel; public int person; public String name; private String engine; 公車有6個輪子,可載40人 卡車有8個輪子,可載3人 計程車有4個輪子,可載5人

22 Java的物件 範例說明: (1) 當成功編譯此範例後,您會發現目錄底下除了ch7_01.class之外, 還會出現CCar.class檔,這是因為我們除了主類別外,另外又定義了 一個類別CCar。 (2) 第38~44行,定義了CCar類別,該類別下宣告了3個公用等級變數 int wheel、int person、String name,以及一個私用等級變數String engine。 (3) 第12~14行,宣告了CCar類別下的3個物件變數並產生實體,物件 名稱分別為bus,truck,taxi。 (4) 第16~18行,設定bus物件的公用等級變數。第20~22行,設定 truck物件的公用等級變數。第24~26行,設定taxi物件的公用等級變 數。 (5) 第27行是不合法的敘述,因為engine是私用變數,所以不允許外部 程式(非同類別的函式敘述)存取該變數(但允許相同類別下的各級 成員函式存取,詳見下一節)。

23 方法 方法(method)又稱為成員函式,它與成員變數一樣,依據 宣告的封裝等級分為public、private、protected等三種等 級。 並且只有public等級的成員函式可以被外部程式(非同類別的 函式敘述)呼叫執行 而private等級的成員函式只能被其他同類別的成員函式呼叫執 行但不可以被外部程式呼叫執行 至於protected等級的成員函式則留待繼承一章再作說明。 除此之外,若未宣告封裝等級,則成員為package等級。

24 方法 到目前為止,我們了解到private等級的成員變數或函式無法被 外部程式所取用與執行,因此能夠達到物件導向「封裝」的目 的。而public等級的成員變數或函式可以被外部程式所取用與 執行,是物件導向封裝時對外唯一的管道,同時private等級的 成員變數或函式也可以被public等級的成員函式所呼叫 因此我們如果想要取用private等級的成員變數,可以先呼叫 public等級的成員函式,再由public等級的成員函式修改private 等級的成員變數,如此不但達到封裝的目的,也可以在類別中 增加了設計程式的彈性。

25 方法 外部程式存取private等級的資料必須透過public等級的方法來完成

26 方法 定義方法 在上一章我們已經提過如何在主類別內定義函式,由於Java的 函式必定隸屬於某一個類別,故語法大致相同,只不過,您必 須把函式定義放在類別內部。以下是定義方法的詳細語法: 在類別內定義成員函式語法 語法說明: 關於[修飾字]部分,我們暫時省略,而封裝等級則為public、private、 protected或不填。 [封裝等級] [修飾字] class類別名稱 [extends 父類別] [implements介面] { [封裝等級] [修飾字] 回傳值資料型態 method名稱 //定義method method的內容 }

27 方法 定義方法 【範例】 class CMyClass { public void funA() //公用成員函式 ………成員函式定義………
} public int funcB(int m,int n) //公用成員函式 private void funcC() //私用成員函式

28 方法 定義方法 請宣告並定義CMyClass類別中的兩個公用等級的成員函式 funcA與funcB
另外宣告一個私用等級的成員函式funcC,funcC無回傳值,也不接受 任何引數。

29 方法 透過成員函式存取私用性資料變數 私用性(private)資料變數無法被外部程式來存取,但可以透 過同一類別的成員函式(等級無限制)來存取它,以便彈性應 用私用資料變數。 【觀念範例7-2】:透過公用成員函式存取私用資料與成員函 式。 範例7-2:ch7_02.java(隨書光碟 myJava\ch07\ch7_02.java)

30 方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 /* 檔名:ch7_02.java 功能:透過公用成員函式存取私用資料與成員函式 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X = new CMyClass(); CMyClass Y = new CMyClass(); X.initVar(); //在X物件上,執行initVar成員函式 Y.initVar(); //在Y物件上,執行initVar成員函式 X.addVar(10); //在X物件上,執行addVar成員函式 System.out.print("物件X\t"); X.showVar(); System.out.print("物件Y\t"); Y.addVar(5); //在Y物件上,執行addVar成員函式 Y.showVar();

31 方法 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 System.out.print("物件Y\t"); Y.addVar(3); //在Y物件上,執行addVar成員函式 Y.showVar(); } class CMyClass { public void initVar() Var=1; public void addVar(int b) Var=Var+b; public void showVar() realShow(); //執行private等級的函式 private int Var; private void realShow() System.out.println("Var=" + Var);

32 方法 透過成員函式存取私用性資料變數 執行結果: 範例說明:
(1) 第34~45行,定義了3個公用的成員函式,可以被外部程式執行。 第46~50行,宣告了1個私用的變數及定義了一個私用成員函式,不 可以被外部程式存取與執行。 (2) 變數Var與成員函式realShow雖然不能夠被外部程式存取與執行, 但可以被同一類別的成員函式存取與執行,例如第36、40、44行。 (3) 程式執行時,記憶體內部呈現下列變化。 Step1:第12~13行執行完畢,記憶體中將同時存在兩個物件變數X,Y以及 它的實體。由於我們並未定義建構子,因此Java會執行預設的建構子(不 做任何事),並且所有的成員都會被自動初始化。由於Var是int型態,故 為0。 下圖是記憶體的變化,由於尚未介紹static method,故省略main在記憶 體資料區的狀況 物件X Var=11 物件Y Var=6 物件Y Var=9

33 方法 透過成員函式存取私用性資料變數

34 方法 透過成員函式存取私用性資料變數 Step2:執行第15行,執行完畢時,X的成員變數Var被設定為1。(下圖中, 我們省略了部分的記憶體程式區)

35 方法 透過成員函式存取私用性資料變數 Step3:執行第16行,執行完畢時,Y的成員變數Var被設定為1。

36 方法 透過成員函式存取私用性資料變數 Step4:執行第18行,執行完畢時,X的成員變數Var被設定為11。

37 方法 透過成員函式存取私用性資料變數 Step5:執行第19~20行,執行完畢時,印出X的成員變數Var為11
Step6:執行第23行,執行完畢時,Y的成員變數Var被設定為6

38 方法 透過成員函式存取私用性資料變數 Step7:執行第24行,執行完畢時,印出Y的成員變數Var為6。

39 方法 透過成員函式存取私用性資料變數 Step9:執行第28行,執行完畢時,印出Y的成員變數Var為9。 在範例7-2中,我們必須先呼叫initVar函式將成員變數的初始值 設定為1。是否有更簡便的方式可以進行這樣的工作呢? 答案是有的 第一種方式是將成員變數於宣告時設定初始值(如範例7-3) 另一種方式則是透過建構子來設定(如範例7-4)。 【觀念範例7-3】:改寫範例7-2,將成員變數設定初始值,完 成相同的初值設定效果。 範例7-3:ch7_03.java(隨書光碟 myJava\ch07\ch7_03.java)

40 方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 /* 檔名:ch7_03.java 功能:成員變數設定初始值 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X = new CMyClass(); CMyClass Y = new CMyClass(); X.addVar(10); //在X物件上,執行addVar成員函式 System.out.print("物件X\t"); X.showVar(); System.out.print("物件Y\t"); Y.addVar(5); //在Y物件上,執行addVar成員函式 Y.showVar(); Y.addVar(3); //在Y物件上,執行addVar成員函式 }

41 方法 執行結果:(同範例7-2) 範例說明: 第39行,Var成員變數被設定了初始值為1,因此不需要initVar()函式 ,因為當物件實體產生時,物件的Var成員就被設定為1。 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 } class CMyClass { public void addVar(int b) Var=Var+b; public void showVar() realShow(); //執行private等級的函式 private int Var=1; //設定初始值 private void realShow() System.out.println("Var=" + Var);

42 Practice 1 設計一個三角形類別 edge1 private int edge2 private int
設計一個方法(public),可計算三角形的周長。在主類別 印出結果。

43 建構子 在範例7-2中,我們必須先呼叫initVar函式將成員變數的 初始值設定為1。雖然這個工作可以透過設定成員變數初 始值來完成(如範例7-3),但當我們希望初始值與物件 實體產生時有關而非一個單純的常數時,就無法單單透 過設定成員變數初始值來完成了。

44 建構子 如果在產生物件實體時,能夠自動幫我們呼叫某個特定 函式,進行某些初始化動作,不是使得設計程式方便多 了嗎?
是的,Java也考慮到了這一點,而且我們可以在建構子中來完 成這些事情。 建構子(Constructor)又稱建構函式,它是產成物件實體時 會自動執行的函式。由於它很特別,因此定義語法與一 般成員函式有些不同,語法如下:

45 建構子 語法說明: (1)建構函式名稱一定要和類別名稱相同。
(2)不可加上回傳值型態,連void也不行。如果加上回傳值型態(含 void)則不是建構函式,所以不會在物件實體產生時自動執行。 (3)沒有任何修飾字。 (4)建構函式只能被new運算子於產生物件實體時自動呼叫,無法讓物 件自由呼叫。 (5)封裝等級一般宣告為public等級。如果宣告為private等級,則只有 其他建構函式可以呼叫它。無法被new自動呼叫。 [封裝等級] 建構函式名稱(引數串) //建構函式名稱就是類別名稱 { ……建構函式內容…… }

46 建構子 【觀念範例7-4】:使用建構函式改寫範例7-2,使其成為建構 函式以自動進行成員變數的初始化
範例7-4:ch7_04.java(隨書光碟 myJava\ch07\ch7_04.java) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /* 檔名:ch7_04.java 功能:建構函式 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X = new CMyClass(1); //自動呼叫建構函式 CMyClass Y = new CMyClass(2); //自動呼叫建構函式 X.addVar(10); //在X物件上,執行addVar成員函式 System.out.print("物件X\t");

47 建構子 執行結果: 物件X Var=11 物件Y Var=7 物件Y Var=10 17 18 19 20 21 22 23 24 25
26 27 28 29 30 31 32 33 34 : 48 X.showVar(); System.out.print("物件Y\t"); Y.addVar(5); //在Y物件上,執行addVar成員函式 Y.showVar(); Y.addVar(3); //在Y物件上,執行addVar成員函式 } class CMyClass { public CMyClass(int i) Var=i; ...同範例7-2的第38~50行... 物件X Var=11 物件Y Var=7 物件Y Var=10

48 建構子 範例說明: (1)第31~34行,定義建構函式,建構函式名稱一定要和類別名稱相同 。 (2)第12行,宣告物件變數X並產生實體,當實體產生時,就會自動立 刻執行該類別的建構函式,也就是執行第31~34行程式。第13行亦同 理。如果將第13行傳入的引數改為『1』,則執行結果同範例7-2。 建構子的多載 上一章所提到的多載功能不但可以應用於一般成員函式,也可 以應用於建構函式,因此,藉由定義多個不同引數(或不同資 料型態)的建構函式,將能夠提供物件實體初始化時更大的彈 性。

49 建構子 建構子的多載 【觀念範例7-5】:多載建構函式,使得在物件實體產生時, 可以依照不同情況執行不同的建構函式。
範例7-5:ch7_05.java(隨書光碟 myJava\ch07\ch7_05.java) 1 2 3 4 5 6 7 8 9 /* 檔名:ch7_05.java 功能:建構函式的多載 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 {

50 建構子 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public static void main(String args[]) { CMyClass X = new CMyClass(); //實體產生時無引數 CMyClass Y = new CMyClass(5,40); //實體產生有兩個整數引數 CMyClass Z = new CMyClass(20.2,30.6); //實體產生有兩個浮點數引數 X.showVar(); Y.showVar(); Z.showVar(); } class CMyClass public double VarA; private double VarB; public CMyClass() //定義無引數的建構函式 VarA=10; VarB=10; public CMyClass(int a,int b) //定義兩個整數引數的建構函式 VarA=a; VarB=a+b;

51 建構子 執行結果: 範例說明: (1)第26~40行是3個建構函式的定義,其署名不相同,符合多載的規 定。並且其內的建構內容也可以不同。
36 37 38 39 40 41 42 43 44 45 46 public CMyClass(double a,double b) //定義兩個浮點數引數的建構函式 { VarA=a; VarB=a*b; } public void showVar() System.out.println("VarA=" + VarA); System.out.println("VarB=" + VarB); VarA=10.0 VarB=10.0 VarA=5.0 VarB=45.0 VarA=20.2 VarB=618.12

52 建構子 範例說明: (2)第12行產成X物件實體,由於沒有引數,所以會執行第26~30行的 建構函式。第13行生成Y物件實體,由於有2個int整數引數,所以會 執行第31~35行的建構函式。第14行生成Z物件實體,由於有2個 double浮點數引數,所以會執行第36~40行的建構函式。

53 建構子 預設的建構子 如果您未定義建構函式,則Java編譯器會自動產生一個內建的 預設建構函式(Default Constructor)到程式中,函式內容為空, 也沒有引數,格式如下: 正因為有此預設的建構函式,所以在之前的範例中,有時我們並未定 義建構函式,但編譯仍不會出錯。 但是如果您已經定義了一個以上的建構函式時,Java編譯器便會認定 您已經準備好所有的建構函式,此時將不會再產生預設建構函式,而 若您沒有建立一個無引數的建構函式,卻又於產生物件實體時不傳入 引數,則會發生錯誤,請見以下的範例。 public 類別名稱() //預設的建構函式 { }

54 建構子 【觀念範例7-6】:取消預設建構函式的注意事項
範例7-6:ch7_06.java(隨書光碟 myJava\ch07\ch7_06.java) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 /* 檔名:ch7_06.java 功能:預設的建構子 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X = new CMyClass(5,40); //實體產生有兩個整數引數 //CMyClass Y = new CMyClass(); //無法找到對應的建構子 X.showVar(); //Y.showVar(); }

55 建構子 執行結果: 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class CMyClass { public int VarA; private int VarB; public CMyClass(int a,int b) //定義兩個整數引數的建構函式 VarA=a; VarB=a+b; } public void showVar() System.out.println("VarA=" + VarA); System.out.println("VarB=" + VarB); VarA=5 VarB=45

56 建構子 範例說明: 第13行的註解如果取消,則會發生錯誤,因為預設的建構函式並不會 產生,故找不到對應的建構函式可執行。所以在定義建構函式時,應 該先定義一個無引數的建構函式(函式內容可以暫時為空),以避免 這樣的狀況。 回收物件實體 在Java中,想要釋放物件實體,只要將所有參考到該物件實體 的物件變數都設為null或指向其他實體,則Java的回收機制就會 在一段時間後自動回收該物件實體的記憶體空間。 而其他程式語言(例如C++)則提供了delete與解構函式,需要使用 者手動關心物件釋放的後續動作。

57 Practice 2 設計一個人事資料類別 CpersonData name: string public
degree: string public p_id: string private salary: int private 建立一個無引數建構子,int 設為0,string 設為 XXXX 建立一個可接受 4 個引數的建構子 show() 函式輸出姓名、p_id 及薪資 由鍵盤輸入資料,並輸出結果

58 物件引數的傳參考值呼叫 在呼叫函式時,引數也可以是物件,在前面的範例中, 我們曾經示範過傳遞字串物件。當時我們曾經提及,傳 遞字串物件,事實上採用的是傳「參考值」呼叫,因為 物件變數本身是一個參考而非實體。 當我們要傳遞一個自行定義的類別所宣告的物件變數時 ,同樣採用的是傳「參考值」呼叫,因此,呼叫端與被 呼叫端可以共用一個物件實體。

59 物件引數的傳參考值呼叫 在下面這個範例中,我們將傳遞物件,並且將使用成員函式多 載進行不同資料型態的加法。
【觀念範例7-7】:使用多載設計成員函式, 並且接受引數為其他類別的物件。 在本範例中,我們將把加法函式擴充到 二維向量的加法,範例如下: 範例7-7:ch7_07.java(隨書光碟 myJava\ch07\ch7_07.java)

60 物件引數的傳參考值呼叫 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 /* 檔名:ch7_07.java 功能:傳遞物件與接收物件 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CVector2 i = new CVector2(); i.set(20,40); CVector2 j = new CVector2(); j.set(15,45); CVector2 k; //k是CVector2物件變數,在第18行用來接收回傳值 CMyClass X = new CMyClass(); k=X.sum(i,j); System.out.println("Vector i=(" + i.x + "," + i.y + ")"); System.out.println("Vector j=(" + j.x + "," + j.y + ")"); System.out.println("Vector k=i+j=(" + k.x + "," + k.y + ")"); } class CMyClass public int sum(int a,int b)

61 物件引數的傳參考值呼叫 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 { return a+b; } public double sum(double a,double b) public CVector2 sum(CVector2 a,CVector2 b) //二維向量的加法成員函式 CVector2 tempVector = new CVector2(); tempVector.x=a.x+b.x; tempVector.y=a.y+b.y; return tempVector; class CVector //二維向量類別 public int x,y; //二維向量的兩項元素資料 public void set(int m,int n) //用於設定二維向量的兩項元素資料 x=m; y=n;

62 物件引數的傳參考值呼叫 執行結果: 範例說明:
(1) 我們在第45~53行,宣告了另一個類別CVector2,用來代表二維向 量。並提供一個set成員函式在第48~52行。 (2) 除了整數與浮點數的加法,在第36~42行,我們又增加了CMyClass 的另一個成員函式sum,它接受的引數是兩個CVector2類別的物件, 並且回傳一個CVector2類別的物件,它會做二維向量的加法,並回傳 二維向量。 (3) 第12~13行,宣告一個CVector2類別的物件i並產生實體,且設定 成員變數為(20,40)。 Vector i=(20,40) Vector j=(15,45) Vector k=i+j=(35,85)

63 物件引數的傳參考值呼叫 範例說明: (4) 第14~15行,宣告一個CVector2類別的物件j並產生實體,且設定 成員變數為(15,45)。 (5) 第16行,宣告一個CVector2類別的物件變數k。 (6) 第17行,宣告一個CMyClass類別的物件X並產生實體。 (7) 第18行,透過X物件的sum成員函式,幫我們做二維向量的加法, 所以k向量=(35,85)。 (8) 在第18行的函式呼叫,i物件的參考傳送給對應的a物件參考,故i 與a實際上指向同一個物件實體。j與b亦同理。 (9) 在第16行時,k是一個物件參考,初始值為null,而第18行時,由 於第41行會回傳一個物件實體位址,所以k儲存該位址後,可以指向 物件的實體。

64 this關鍵字 this是一個特殊的關鍵字,在撰寫程式時代表類別的本身 ,在實際執行時,則代表物件的本身。

65 this關鍵字 區域變數與成員變數同名 在前面曾經提及,如果是類別內的敘述,則使用類別內的成員 時,不用加上物件名稱(例如範例7-8的第43、44行)。 而如果在函式中定義了區域變數,就有可能與成員變數同名,此時, 取用該名稱的變數會是區域變數還是成員變數呢? 由於區域變數的宣告較靠近存取敘述,因此取用的將是區域變數,請見下 列範例。 【觀念範例7-9】:區域變數與成員變數同名的探討。 範例7-9:ch7_09.java(隨書光碟 myJava\ch07\ch7_09.java)

66 this關鍵字 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 /* 檔名:ch7_09.java 功能:區域變數與成員變數同名 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X = new CMyClass(); X.show(); } class CMyClass public int var=10; //成員變數 public void show() int var=20; //區域變數 System.out.println("var=" + var); //將會取用到區域變數

67 this關鍵字 區域變數與成員變數同名 執行結果: 範例說明:
從執行結果中,我們發現取用到的是區域變數var,而非成員變數var ,那麼我們如果在show()函式內要取用成員變數var該怎麼辦呢?此時 必須搭配this關鍵字來取用。 var=20

68 this關鍵字 this關鍵字的簡易使用法
this關鍵字是一個非常特別的關鍵字,對於任何類別而言,this 就是代表著該類別本身,當類別產生物件實體後,則物件的 this代表物件實體本身 因此,如果要使得範例7-9能夠取用到成員變數,可以透過this關鍵字 來完成。 【觀念範例7-10】:改寫範例7-9,使得區域變數與成員變數 都能夠被印出。 範例7-10:ch7_10.java(隨書光碟 myJava\ch07\ch7_10.java)

69 this關鍵字 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 /* 檔名:ch7_10.java 功能:this關鍵字的簡易使用法 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X = new CMyClass(); X.show(); } class CMyClass public int var=10; //成員變數 public void show() int var=20; //區域變數 System.out.println("區域變數var=" + var); System.out.println("成員變數var=" + this.var);

70 this關鍵字 this關鍵字的簡易使用法 執行結果: 範例說明:
在這個範例中,我們發現如果區域變數與成員變數不同名的話,使用 與不使用this關鍵字並沒有差別。那麼this關鍵字的功用是否僅止於此 呢?事實上並不是的,不過我們應該先深入探討this的真正涵意以及 實作上的變化,然後再來討論this的用途。 區域變數var=20 成員變數var=10

71 this關鍵字 深入探討this關鍵字 在前面我們已經說明this是可以於實作時期(程式執行時), 當作物件本身來使用。因此上述範例的this,代表的就是物件 X。如果在其他類別中(例如主類別main函式中),我們要取 用物件X的var變數值,可透過「X.var」來達成,而在X的方法 中,則可以透過「this.var」來達成,因為this就是X。 而this是X的什麼呢? 從「X.var」中的X可以得知,X在Java中扮演的是一個物件的參考, 故this實際上是代表物件本身的參考。 假設X的實體位址為3100,則this也是3100,所以對於JVM而言,不論 遇到「X.var」或「this.var」,它看到的都是存取3100位址的物件實 體中的成員變數var。

72 this關鍵字 深入探討this關鍵字 事實上,不論我們在程式中是否出現this關鍵字,Java編譯器在 編譯類別時,都會自動多出隱含的參考變數this,並且this並不 算是類別的成員,而且只能在類別中使用。 this變數被設定其值的時機,將會是遇到「new 類別名稱()」時 ,由於new代表產生類別的物件實體,故會有一個實體的開始 位址,在Java中,我們將該位址稱為是物件的參考(reference), 而當new指令執行完畢時,this變數就被設定為該物件的參考 。 而在範例7-10中,第13行執行完畢時,不但X被設定為物件的參考, this也被設定為物件的參考。

73 this關鍵字 深入探討this關鍵字 事實上,this()代表的是呼叫該類別的建構函式,不過這樣的語 法只能出現在建構函式的第一行
而在之前的圖示中,我們有時候會看到物件實體內包含了成員函式, 但它未包含完整的成員函式內容,事實上,它的作用只是用來呼叫程 式段的成員函式實作。

74 this關鍵字 深入探討this關鍵字 而由於每一個物件都可能去執行程式段的成員函式,故對於程式段的 成員函式而言,它必須知道是哪一個物件要求執行它,以便於當它要 取用成員變數時,知道要取用哪一個物件的成員變數。如下圖示意:

75 this關鍵字 深入探討this關鍵字 正因為程式段的成員函式需要知道是哪一個物件呼叫它,故 Java的做法是,在編譯時期,編譯器會對所有的成員函式多加 一個隱含的final引數,該引數的型別是類別本身,正如同宣告 物件變數一樣,該引數也就是一個參考,而該引數將會填入物 件的參考值,並以this在類別內進行操作,如此才能夠在呼叫 成員函式時,提供函式判斷是哪一個物件呼叫它,並且取用到 正確的成員變數 而正由於this是被宣告為final引數,故只有在呼叫時能被設定, 之後就不能再被設定了。 因此上圖應該修改為下圖才是完整的圖示。

76 this關鍵字 深入探討this關鍵字 this的作用

77 this關鍵字 深入探討this關鍵字 在上圖中,如果是X的show函式要求執行程式段的show函式, 則會傳入X的參考,也就是3100,因此,程式段的show函式在 取用this.var變數時,知道要取用處於3100位址的物件實體的成 員變數var 現在我們算是徹底瞭解了this,以下,我們透過一個範例來觀 察,this的內容究竟為何? 【觀念範例7-11】:觀察this變數內容,以求得物件實體的所 在位址。 範例7-11:ch7_11.java(隨書光碟 myJava\ch07\ch7_11.java)

78 this關鍵字 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 /* 檔名:ch7_11.java 功能:this的內容 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X = new CMyClass(); CMyClass Y = new CMyClass(); System.out.print("X物件實體所在位址="); X.show_this(); System.out.print("Y物件實體所在位址="); Y.show_this(); } class CMyClass public int var=10; //成員變數 public void show_this()

79 this關鍵字 深入探討this關鍵字 執行結果: 範例說明:
從執行結果中,我們可以得知X物件的實體所在位址為「00c17164」 ,而Y物件的實體所在位址為「01fb8ee3」。 26 27 28 29 { System.out.println(this); }

80 this關鍵字 this關鍵字的使用時機 總結上述的介紹,我們可以將this關鍵字的使用時機整理如下 :
1.取得物件實體的參考:如同範例7-11。 2.區別成員變數與區域變數:如同範例7-10。 3.用以作為物件本身,例如進行物件的比較:請見範例7-13。 4.在建構函式內,藉以呼叫其他的建構函式:使用的是this(引數串)格 式,語法如下,請見範例7-12。

81 this關鍵字 this關鍵字的使用時機 使用this(引數串)呼叫建構函式語法:
範例7-12:ch7_12.java(隨書光碟 myJava\ch07\ch7_12.java) [封裝等級] 建構函式名稱(引數串) //建構函式名稱就是類別名稱 { this(引數1,引數2,…); //必須是函式的第一個敘述 ……建構函式的其餘內容…… }

82 this關鍵字 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 /* 檔名:ch7_12.java 功能:在建構函式中使用this(引數列) */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X = new CMyClass(3); //實體產生時呼叫第24行的建構函式 CMyClass Y = new CMyClass(5,40);//實體產生時呼叫第31行的建構函式 X.showVar(); Y.showVar(); } class CMyClass public int VarA; private int VarB; public CMyClass(){} //良好的習慣是補上一個沒有引數的建構函式 public CMyClass(int i) //定義一個整數引數的建構函式

83 this關鍵字 執行結果: VarA=1 VarB=3 VarA=200 VarB=40 26 27 28 29 30 31 32 33
34 35 36 37 38 39 VarA=1; VarB=i; } public CMyClass(int a,int b) //定義兩個整數引數的建構函式 { this(b); //呼叫第24行的建構函式,藉以設定VarB VarA=a*b; public void showVar() System.out.println("VarA=" + VarA); System.out.println("VarB=" + VarB); 執行結果: VarA=1 VarB=3 VarA=200 VarB=40

84 this關鍵字 this關鍵字的使用時機 範例說明: 【觀念及實用範例7-13】:兩物件的比較。
在第31行,將設定VarB的工作交給第24行的建構函式完成,雖然它也 會設定VarA,但第32行會重新計算VarA的值。使用this(引數串)呼叫 建構函式,必須在建構函式中才能使用,並且必須是第一個敘述。 【觀念及實用範例7-13】:兩物件的比較。 範例7-13:ch7_13.java(隨書光碟 myJava\ch07\ch7_13.java)

85 this關鍵字 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 /* 檔名:ch7_13.java 功能:物件的比較 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X = new CMyClass(5); CMyClass Y = new CMyClass(5); CMyClass Z = X; System.out.print("物件X與物件Y "); X.compare2Obj(Y); System.out.print("物件X與物件Z "); X.compare2Obj(Z); } class CMyClass private int Var; public CMyClass(){} //良好的習慣是補上一個沒有引數的建構函式

86 this關鍵字 執行結果: 物件X與物件Y 兩物件不相等 物件X與物件Z 兩物件相等 26 27 28 29 30 31 32 33 34
35 36 37 38 public CMyClass(int i) //一個整數引數的建構函式 { Var=i; } public void compare2Obj(CMyClass Obj) if(this==Obj) System.out.println("兩物件相等"); else System.out.println("兩物件不相等"); 物件X與物件Y 兩物件不相等 物件X與物件Z 兩物件相等

87 this關鍵字 this關鍵字的使用時機 範例說明:
(1)在第33行進行兩物件的比較,其中this將會是物件本身的參考,例 如第16、18行,由於是由X執行該函式,故this代表X。而Obj則是傳 入的引數,例如第16行的呼叫,則Obj代表Y,第18行的呼叫,則Obj 代表Z。 (2)從執行結果中,我們可以發現物件的比較事實上是參考的比較。 而非實體內容的比較。這是因為不論是物件名稱或this,代表的都是 一個參考,而相等比較『==』代表的是比較兩個參考值是否相同。 所以如果兩個參考值不同(指向不同的實體),即使所指向的實體「 內容」完全相同,也不會被判斷為相等。

88 物件陣列 物件也可以存放於陣列中,只不過存放的將會是物件的 參考,因此,要使用物件陣列,至少需要使用兩次以上 的new運算子。語法如下:
【語法說明】 (1)第一行是宣告一維物件陣列,並產生陣列實體。同樣的,它可以 分解為兩行如下。 類別名稱 陣列名稱[] = new 類別名稱[物件數量]; for(int i=0;i<陣列名稱.length;i++) { 陣列名稱[i]=new 類別名稱(引數串列); //為每一個陣列元素產生物件實體 } 類別名稱 陣列名稱[]; //宣告陣列名稱 陣列名稱 = new 類別名稱[物件數量]; //產生陣列實體

89 物件陣列 【語法說明】 (2)由於每一個陣列元素代表每一個物件的參考,所以我們可以透過 迴圈逐次產生各個物件實體。如果您想要呼叫的建構函式不同,則可 以將迴圈展開,手動逐個產生各個物件實體,如下範例: 陣列名稱[0]=new 類別名稱(引數串列); 陣列名稱[1]=new 類別名稱(引數串列); 陣列名稱[2]=new 類別名稱(引數串列); :

90 物件陣列 【範例1】宣告一個包含10個字串物件的陣列strArr,初始內容 為空。
String strArr[] = new String[10]; for(int i=0;i<strArr.length;i++) { strArr[i]=new String(); //為每一個陣列元素產生物件實體 }

91 物件陣列 【範例2】宣告一個包含7個字串物件的陣列strArr,初始內容 為各星期的英文單字。
【說明】由於要藉由建構函式建置不同的字串內容,故將迴圈 展開手動來設定引數。 String strArr[] = new String[7]; strArr[0]=new String("Sunday"); //為陣列元素strArr[0]產生物件實體 strArr[1]=new String("Monday"); //為陣列元素strArr[1]產生物件實體 strArr[2]=new String("Tuesday"); //為陣列元素strArr[2]產生物件實體 strArr[3]=new String("Wendesday"); //為陣列元素strArr[3]產生物件實體 strArr[4]=new String("Thursday"); //為陣列元素strArr[4]產生物件實體 strArr[5]=new String("Friday"); //為陣列元素strArr[5]產生物件實體 strArr[6]=new String("Saturday"); //為陣列元素strArr[6]產生物件實體

92 物件陣列 【觀念範例7-14】:建立一個物件陣列,並透過引數設定,觀 察建構函式的執行狀況。
範例7-14:ch7_14.java(隨書光碟 myJava\ch07\ch7_14.java) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 /* 檔名:ch7_14.java 功能:物件陣列與建構函式 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X[] = new CMyClass[3]; System.out.println(" "); for(int i=0;i<X.length;i++) X[i] = new CMyClass()

93 物件陣列 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 CMyClass Y[] = new CMyClass[3]; System.out.println(" "); for(int i=0;i<Y.length;i++) Y[i] = new CMyClass(i+10); } class CMyClass { public int VarA; private int VarB; public CMyClass() //無引數的建構函式 System.out.println("無引數的建構函式執行中"); public CMyClass(int i) System.out.println("有引數的建構函式執行中,引數為" + i);

94 物件陣列 執行結果: 範例說明: 利用第13、18行的列印,我們可以得知,物件的建構函式會等到實際 產生物件實體時才進行,而不會在產生物件陣列實體時進行,因為物 件陣列內的元素只是物件的參考而已。 無引數的建構函式執行中 有引數的建構函式執行中,引數為10 有引數的建構函式執行中,引數為11 有引數的建構函式執行中,引數為12

95 物件陣列 傳遞物件陣列 我們時常會有需要將物件陣列傳遞給某個函式,進行更進一步 的應用。傳遞物件陣列和傳遞一般陣列的語法差不多,只不過 是將原始資料型態改為類別名稱而已,請見下列範例。 【觀念範例7-15】:觀察物件陣列中,每個元素的參考值。藉 以了解物件實體在記憶體的配置情形。 範例7-15:ch7_15.java(隨書光碟 myJava\ch07\ch7_15.java)

96 物件陣列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 /* 檔名:ch7_15.java 功能:傳遞物件陣列與物件配置情形 */ package myJava.ch07; import java.lang.*; public class ch7_ //主類別 { public static void main(String args[]) CMyClass X[] = new CMyClass[5]; for(int i=0;i<X.length;i++) X[i] = new CMyClass(); COtherClass Obj = new COtherClass(); Obj.show(X); } class COtherClass public void show(CMyClass X[]) System.out.println("物件X[" + i + "]實體的位址在" + X[i]);

97 物件陣列 傳遞物件陣列 執行結果: 範例說明: (1)第16行Obj物件呼叫show函式時,將物件陣列當作引數傳入函式中 。
26 27 28 29 30 31 32 33 } class CMyClass { public int VarA; private int VarB;

98 物件陣列 傳遞物件陣列 範例說明: (2)在show函式中,我們列印X[i]的內容,會列印出每個物件的參考位 址,您可以發現,雖然陣列元素X[0]~X[5]會位於連續的記憶體位址 ,但實際的物件並不一定會位於連續的記憶體位址。參考圖示如下:


Download ppt "物件導向程式設計 參考書目: 1. 洪維恩,C++ 教學手冊 第三版,旗標出版圖書公司。 2. 陳錦揮,Java 初學指引,博碩文化 3"

Similar presentations


Ads by Google