Download presentation
Presentation is loading. Please wait.
1
物件導向系統分析與設計 CH04 物件導向開發方法
2
物件導向開發方法的效益 物件的概念比較自然: 物件類別可以重覆使用:
物件導向方法的特性與人們觀察世界的方式相符,也就是與人們以物件類別的觀點討論工作與系統需求的傾向是一致的。 物件類別可以重覆使用: 類別與物件只需要建立一次,就可以多次使用
3
認識物件導向的概念 物件、屬性與方法: 類別: 物件:例如:使用者介面物件,物件中含有按鈕、功能表項目、文字方塊或標籤等
屬性:帶有數值的物件特徵,例如:按鈕或標籤的大小、形狀、顏色、位置與標題;或是顧客的姓名、地址與電話號碼。 方法:物件的行為或作業,用以描述物件可以執行的工作 類別: 所有類似物件歸屬的類型或分類
4
物件的互動與訊息 物件透過彼此傳送訊息進行互動,它可以要求其他物件啟動,或執行某種方法
5
關聯性與多重性 關聯性:物件間自然發生的關係,像是顧客與它的訂單間產生的關聯 多重性:物件間關聯性的數量
6
封裝與資訊隱藏 封裝:將屬性與方法結合為一單元,並隱藏物件的內部結構 資訊隱藏:外部世界無法看到與物件相關的資料
識別值:具有唯一性的物件參照,可以讓其他的物件找到它,並將訊息傳送給它
7
繼承與多型 繼承:某一個類別與另一個類別共用某些特性
一般化/特殊化階層:一個分類體系統,在結構上會從比較一般性的父類別,往下延伸為比較特殊化的子類別,也被稱為繼承階層 父類別:可以讓子類別執行延伸的作業 子類別:具有額外的屬性與方法,這些都與它所延伸的一般性類別不同。 多型:不同的物件可以使用自己的方式回應相同的訊息。
8
繼承 繼承是物件導向程式設計的重要觀念 繼承是一個類別含括現存類別的部份或全部的成員資料或成員方法,並且新增額外的成員資料或方法,或是覆寫或隱藏繼承類別的方法或變數
9
類別的繼承-說明 當一個類別是繼承自其它類別,我們稱這個類別為繼承類別的「子類別」(Subclass)或「延伸類別」(Derived Class),繼承的類別稱為「父類別」(Superclass)或「基礎類別」(Base Class)。例如:類別Nissan是繼承自類別Car,繼承關係如右圖所示:
10
繼承的例子 繼承關係: 程式: class A{} class B extends A {} class C extends A {}
class D extends B {} class E extends B {}
11
Java類別的始祖 所有類別的基礎類別 Object 下列兩行的類別定義方式是相同的:
教學網址: 類別list: 下列兩行的類別定義方式是相同的: class A {} class A extends Object {}
12
類別的繼承-兄弟類別 多個子類別繼承同一個父類別,每一個子類別稱為「兄弟類別」(Sibling Classes),如下圖所示:
13
類別的繼承-父類別 父類別Car定義轎車的基本資料,如下所示: class Car { private int engineNum;
private int color; public void setNum(int num) { engineNum=num; } public void setColor(int color) { this.color=color; } public void printVehicle() { } }
14
類別的繼承-子類別 因為車輛分為很多種廠牌,例如:Ford、Nissan和VM等,以轎車Nissan子類別的宣告為例,如下所示:
class Nissan extends Car { private double price; public Nissan(int num, int color, double price) { } public void printNissan() { } }
15
類別的繼承-限制條件 雖然子類別可以繼承父類別的所有成員資料和方法,但是在存取時仍有一些限制,如下所示:
子類別不能存取父類別宣告成private的成員資料和方法。 父類別的建構子不屬於類別成員,所以在子類別並不能繼承父類別的建構子,只能呼叫父類別的建構子。
16
範例1:建立車輛資料(1/4 ) 宣告Car類別,宣告Nissan類別繼承自Car類別 在Nissan類別中新增price成員變數
建立兩台車,一輛為Joe的車,一輛為Jane的車
17
範例1:建立車輛資料(2/ 4) Car類別(car.java) class Car { private int engineNum;
private int color; public void setNum(int num) engineNum = num; } public void setColor(int color) this.color = color; public void printCar() System.out.println("引擎號碼: " + engineNum); System.out.println("色彩: " + color); Ch04/car.java
18
範例1:建立車輛資料(3/4 ) 主程式與子類別Nissan(Ch04_01.java) class Ch04_01 {
public static void main(String [] args) Nissan joe = new Nissan( , 1, ); Nissan jane = new Nissan( , 2, ); joe.setColor(3); joe.printNissan(); jane.printNissan(); } class Nissan extends Car private double price; public Nissan(int num, int color, double price) setNum(num); setColor(color); this.price = price; public void printNissan() System.out.println("===驕車資料=="); printCar(); System.out.println("車價: " + price); Ch04/Ch04_01.java
19
範例1:建立車輛資料(4/4) 結果:
20
活動筋骨和大腦(1) 參考範例1 建立一個Toyota的子類別,繼承Car,並且在Toyota類別中有一個屬性是氣缶量,及一個方法set氣缶
新增兩個物件 C1(12345, 2, 2800) C2(23232, 5, 3500)
21
基本繼承 非private修飾的物件成員都可以被繼承 子類別的物件實體包含父類別的物件實體
22
類別成員與繼承 類別屬性經過繼承之後,還是只有一份資料儲存區。 這份資料儲存區是父類別、子類別、父類別的物件及子類別的物件所共有。
繼承之後,類別成員都還是只有一個
23
範例2:類別成員的測試(1/4) 建立如下的類別和物件
24
範例2:類別成員的測試(2/4) 類別Super3和子類別Sub3 class Super3 {
static String className = "Super3"; String data = "Superdata"; static void setClassName(String n) className = n; } class Sub3 extends Super3 int j = 2;
25
範例2:類別成員的測試(3/4) 主程式 class Ch04_02 {
public static void main(String [] args) Super3 a = new Super3(); Sub3 b = new Sub3(); b.className = "透過子類別物件更改父類別屬性"; System.out.println(a.className); b.setClassName("透過子類別物件呼叫父類別方法"); System.out.println(Sub3.className); } Ch04/Ch04_02.java
26
範例2:類別成員的測試(4/4)
27
活動筋骨和大腦(2) 參考範例1及範例2 修改範例1,在類別Car中加入一個類別屬性count,記錄國內目前有多少車輛
建立一個Toyota的子類別,繼承Car 建立兩台車,分別是wang的車(屬性: ,4, )和toto的車(屬性: , 1, ) 檢查一下,現在國內的車輛應該有幾台? Ch04/Ex04_01.java
28
PRIVATE成員不被繼承 以private宣告的父類別之物件成員不被子類別所繼承。
不被繼承的成員存在子類別物件中的父類別物件內,只是子類別物件無權使用。 子類別物件可以透過父類別的public方法操縱父類別的private屬性。
29
範例3:測試private成員(1/4) class Super4 { private String data = "原始資料";
void setData(String n) { data = n; } String getData() { return data; } } class Sub4 extends Super4 {}
30
範例3:測試private成員(2/4) Sub4型別的b可以使用繼承而來的setData()和getData()。
31
範例3:測試private成員(3/4) 主程式 class Ch04_03 {
public static void main(String [] args) Super4 a = new Super4(); Sub4 b = new Sub4(); //System.out.println(a.data); //System.out.println(b.data); System.out.println("修改data的值之前: "); System.out.println("a的data: " + a.getData()); System.out.println("b的data: " + b.getData()); System.out.println("修改data的值之後: "); b.setData("資料變更"); } Ch04/Ch04_03.java
32
範例3:測試private成員(4/4)
33
重新定義父類別的物件屬性 子類別新定義的成員和父類別的成員實際上是位於不同的領域(scope)。
子類別可重新定義與「父類別物件屬性」同名的屬性。 透過子類別物件參照無法存取已被重新定義的父類別屬性。 子類別的物件方法可以取用父類別的非private之物件屬性。
34
super-父類別物件之參照
35
範例4:重新定義父類別物件屬性及super(1/3)
class Super5 { String data = "原始資料"; String m = "父類別才有的資料"; void setData(String n) { data = n; } String getData() { return data; } } class Sub5 extends Super5 { String data = "Sub的原始資料"; { System.out.println("Sub5的data: " + data); System.out.println("Sub5父類別Super5的data: " + super.data); System.out.println("Sub5父類別Super5的m: " + m); return data;
36
範例4:重新定義父類別物件屬性及super(2/3)
主程式 class Ch04_04 { public static void main(String [] args) Super5 a = new Super5(); Sub5 b = new Sub5(); System.out.println("修改data的值之前: "); System.out.println("a的data: " + a.getData()); System.out.println("b的data: " + b.getData()); System.out.println("修改data的值之後: "); b.setData("資料變更"); } Ch04/Ch04_04.java, Ch04_04_01.java
37
範例4:重新定義父類別物件屬性及super(3/3)
38
建構子與繼承 建構子不被繼承,無法透過子類別名稱去呼叫父類別的建構子。
在父類別及子類別都沒有定義建構子的情形下,建立子類別物件時,父類別的預設建構子會先被呼叫,接著子類別的預設建構子才會被呼叫。 如果是自訂的建構子,父類別的無參數建構子會先被呼叫,接著子類別的無參數建構子才被呼叫。 建立延伸類別的物件時,延伸類別的每個基礎類別之建構子都會被呼叫。
39
使用super()呼叫父類別建構子 super()的功能是呼叫父類別的建構子。
this()和super()都只能在建構子內使用,並且必須出現在建構子的第一個敘述。 this()和super()只能擇一而用,不能同時使用 子類別建構子未使用super(<參數列>)時,編譯器會自動加入預設的父類別建構子呼叫 class 父類別名(){ 父類別名(){} } class 子類別名(){ 子類別名(){ super(); //若無此敘述,則編譯器會自動加入 //程式敘述 子類別名(形式參數列){
40
範例5 class Car5 { static int count; private int serial_num;
class Nissan5 extends Car5 { int color; int engineNum; double price; Nissan5(int num, int color, int no, double price) { super(num, color, no); this.color = 5; engineNum = ; this.price = price; } void printCar() { System.out.print("===="); super.printCar(); System.out.println("轎車資料===="); System.out.println("色彩(父): " + super.color); System.out.println("引擎號碼(父): " + super.engineNum); System.out.println("色彩(子): " + color); System.out.println("引擎號碼(子): " + engineNum); System.out.println("車價: " + price); System.out.println("車輛數: " + count); class Car5 { static int count; private int serial_num; int engineNum; int color; Car5(int num, int color, int no) serial_num = num; this.color = color; engineNum = no; count++; } void printCar() System.out.print("編號: " + serial_num);
41
範例5 class Ch04_05 { public static void main(String [] args)
Nissan5 joe = new Nissan5(1,1, , ); Nissan5 jane = new Nissan5(2,2, , ); joe.printCar(); jane.printCar(); }
42
活動筋骨、大腦時間(2) class MidTerm extends Test class Test { { public int num;
public int numOfStudents; public MidTerm(int no, String name, int numOfStudents) (no, name); .numOfStudents = numOfStudents; } public void printMidTerm() .printTest(); System.out.println("學生人數: " + numOfStudents); System.out.println("子呼叫父super.name : " + super.name); System.out.println("子呼叫name : " + name); System.out.println("子呼叫this.name : " + this.name); class Test { public int num; public String name; public Test(int num, String name) { .num = num; .name = name; } public void printTest() System.out.println("學號no : " + num); System.out.println("姓名name : " + name);
43
活動筋骨、大腦時間(2) 主程式 class Ex04_02 {
public static void main(String [] args) MidTerm mid = new MidTerm(1, "wang", 10); mid.printMidTerm(); }
44
方法的覆蓋(2/4) 覆蓋的原理:先碰到子類別定義之成員
45
方法的覆蓋(3/4) 方法覆蓋的主要用意是「修改原有功能的實作」。 使用 final 宣告的父類別之物件方法不能被覆蓋。
靜態方法無法使用覆蓋(沒有覆蓋的特性)。 覆蓋舊方法時,新定義的方法可以透過 super 參照呼叫舊方法。
46
方法的覆蓋(4/4) 方法覆蓋要注意下列幾點: 方法覆蓋時,沒有領域不同的區別,所有被覆蓋的方法一律打入冷宮。 回傳型別必須相同。
不能縮減方法的存取權限 丟出的例外型別必須相同 方法覆蓋時,沒有領域不同的區別,所有被覆蓋的方法一律打入冷宮。
47
範例1: class Ch05_01 { public static void main(String [] args)
{ Super05_01 a = new Super05_01(); Sub05_01 b = new Sub05_01(); System.out.println("a的data: " + a.showData()); System.out.println("b的data: " + b.showData()); } class Super05_01 {String data = "Super05_01原始資料"; String showData() { return data; } class Sub05_01 extends Super05_01 { String data = "Sub05_01的原始資料"; { return data; }
48
範例2:方法覆蓋時,沒有領域不同的區別,所有被覆蓋的方法一律打入冷宮
class Ch05_02 { public static void main(String [] args) { Super05_02 a = new Super05_02(); Sub05_02 b = new Sub05_02(); a.showData(); b.showData(); } class Super05_02 { String data = "Super05_02原始資料"; void showData() { System.out.println(getData()); } String getData() { return data; } class Sub05_02 extends Super05_02 { String data = "Sub05_02的原始資料"; { return data; }
49
方法的覆蓋(1/4) 子類別的重新定義物件方法稱為方法的覆蓋(Overriding)。 方法覆蓋時,下列各項都必須和父類別定義的方法相同:
方法的回傳型別。 方法名稱。 形式參數列中的型別及順序。 如果子類別定義的方法和父類別定義的方法同名,但參數不同時,只能算是一種多載(overloading)
50
範例3:使用super呼叫父類別方法 class Ch05_03 {
public static void main(String [] args) Super05_03 a = new Super05_03(); Sub05_03 b = new Sub05_03(); System.out.println("a的data: " + a.showData()); System.out.println("b的data: " + b.showData()); } class Super05_03 String data = "Super05_03原始資料"; String showData() { return data; } class Sub05_03 extends Super05_03 { String data = "Sub05_03的原始資料"; { return super.showData(); }
51
抽象類別(1/3) 類別定義中,只要有一個方法(或以上)定義為抽象方法(abstract method),則該類別為抽象類別(abstract class)。 抽象方法並沒有定義方法的主體(沒有實作) 無法利用抽象類別建立物件。 抽象類別的用處是當作父類別,讓子類別繼承。 子類別必須將父類別中的抽象方法實作出來,才能建立物件。
52
抽象類別(2/3) 抽象類別的定義語法: 某個類別的主體內,宣告了抽象方法,則該類別必須宣告為抽象類別。
修飾字 abstract class 類別名稱 { //屬性宣告 修飾字 abstract 型別 方法名稱(參數列); //其它方法定義 } 某個類別的主體內,宣告了抽象方法,則該類別必須宣告為抽象類別。 抽象類別雖然不能用以建立物件,但是可以當作物件的型別,用來宣告參照變數。 抽象類別的子類別若不完全實作抽象方法,則依然是抽象類別。
53
抽象類別(3/3) 使用抽象類別的用意,主要是「制定固定的訊息接收管道,但不把焦點放在訊息的處理上」。
抽象類別和一般類別一樣,都可以定義建構子,只是不能直接以抽象類別的建構子建立物件。 抽象方法的目的就是為了讓子類別實作,所以abstract 不能同時和 final、static 或 private 一起使用。
54
多型(polymorphism) 不論參照的型別為何,呼叫方法時,呼叫最新的覆蓋方法。
多型指的是「使用相同的訊息呼叫,可以進行不同的功能操作」。 動態結合(dynamic binding):當某個物件方法,接收傳入的A類別之物件時,該方法無法得知傳入的是A類別的物件,或A之延伸類別的物件,直到執行時才會知道,也才能知道要呼叫的是哪個方法。
55
多型(polymorphism) vs. 多載(overload)(1/3)
多載: class 液體_05 { String drink; 液體_05(String drink_name) { drink = drink_name; } } class 固體_05 { String food; 固體_05(String food_name) { food = food_name; } class 動物_05 { void 吃(液體_05 a) { System.out.println(a.drink + "是用喝的或吸的!"); } void 吃(固體_05 a) { System.out.println(a.food + "是要用咬的或磨的!"); } class Ch05_05 { public static void main(String [] args) { 液體_05 x1 = new 液體_05("珍珠奶茶"); 固體_05 x2 = new 固體_05("漢堡"); 液體_05 x3 = new 液體_05("水"); 固體_05 x4 = new 固體_05("草"); 動物_05 牛 = new 動物_05(); 動物_05 人 = new 動物_05(); System.out.println("== 牛 =="); 牛.吃(x3); 牛.吃(x4); System.out.println("== 人 =="); 人.吃(x1); 人.吃(x2); } Ch05_05.java
56
多型(polymorphism) vs. 多載(overload)(2/3)
class 動物_06 { String kind; void 吃(液體_06 a) { System.out.println(a.drink + "是用喝的或吸的!"); } void 吃(固體_06 a) { System.out.println(a.food + "是要用咬的或磨的!"); } } class 人_06 extends 動物_06 { 人_06() { kind = "人"; } { System.out.println(a.drink + "是用喝的!"); } { System.out.println(a.food + "是用咬的!"); } class 牛_06 extends 動物_06 { 牛_06() { kind = "牛"; } { System.out.println(a.drink + "是用吸的!"); } { System.out.println(a.food + "是用磨的!"); } Ch05_06.java
57
多型(polymorphism) vs. 多載(overload)(3/3)
class Ch05_06 { public static void main(String [] args) { 液體_06 x1 = new 液體_06("珍珠奶茶"); 固體_06 x2 = new 固體_06("漢堡"); 液體_06 x3 = new 液體_06("水"); 固體_06 x4 = new 固體_06("草"); 牛_06 y1 = new 牛_06(); 人_06 y2 = new 人_06(); System.out.println("== " + y1.kind + " =="); y1.吃(x3); y1.吃(x4); System.out.println("== " + y2.kind + " =="); y2.吃(x1); y2.吃(x2); } class 液體_06 { String drink; 液體_06(String drink_name) { drink = drink_name; } } class 固體_06 { String food; 固體_06(String food_name) { food = food_name; }
58
物件的型別轉換 子類別物件也屬於父類別物件 小紅是一條魚。 小紅是一隻脊椎動物。 小紅是一隻動物。
59
範例4: class Ch05_07 { public static void main(String [] args)
液體_07 x1 = new 液體_07("珍珠奶茶"); 固體_07 x2 = new 固體_07("漢堡"); 液體_07 x3 = new 液體_07("水"); 固體_07 x4 = new 固體_07("草"); 動物_07 y1 = new 牛_07(); 動物_07 y2 = new 人_07(); System.out.println("== " + y1.kind + " =="); y1.吃(x3); y1.吃(x4); System.out.println("== " + y2.kind + " =="); y2.吃(x1); y2.吃(x2); } Ch05_07.java
60
物件的型別轉換- 異質集合 相同類別的物件集合稱為同質集合(homogenous collections)。
不同類別的物件集合稱為異質集合(heterogeneous collections)。 基本型別的陣列為同質集合。 當父類別型別的參照陣列之元素分別指向不同的子類別物件時,此參照陣列稱為異質集合。 異質集合建立在父類別型別參照變數可以指向子類別物件的原理上。
61
物件的型別轉換- 異質集合的物件陣列 異質集合的物件陣列
62
範例5 class Ch05_08 { public static void main(String [] args)
液體_08 x1 = new 液體_08("珍珠奶茶"); 固體_08 x2 = new 固體_08("漢堡"); 液體_08 x3 = new 液體_08("水"); 固體_08 x4 = new 固體_08("草"); 動物_08 y[] = {new 牛_08(), new 人_08()}; int i; for(i= 0; i<2; i++) System.out.println("== " + y[i].kind + " =="); y[i].吃(x1); y[i].吃(x2); y[i].吃(x3); y[i].吃(x4); }
63
物件的強制型別轉換(1/3) 物件型別轉換,其實是針對指向物件的參照變數,而不是針對物件實體。物件實體只要被建立,其佔用的記憶體位置及大小都不會被變更。 物件的強制型別轉換之語法 (目的類別)物件參照變數 物件參照變數所指向的物件實體,必須是目的類別的物件實體,或是其子類別的物件實體。
64
物件的強制型別轉換(2/3) 子類別物件轉換成父類別物件
65
物件的強制型別轉換(3/3) 父類別物件不具備子類別定義之成員,無法轉換成子類別物件。
66
INSTANCEOF運算子 instanceof運算式會得到一個布林值,若物件名稱所指向的物件實體屬於欲判斷的類別則回傳true;反之,回傳false。 物件名稱 instanceof 類別名稱 物件名稱所屬的參照型別必須和類別名稱有繼承關係,否則會發生錯誤。 instanceof的優先權和關係運算子的 <、>、<=、>= 相同,它們的運算結果都是布林值。
67
動腦動手時間(1) 請以範例4,5,6,7,8為參考 建立一個程式: 人和牛要吃所有的食物 食物類別:食物名稱 動物類別:吃() 液體類別
固體類別 動物類別:吃() 人類別:吃(固體), 吃(液體) 牛類別:吃(固體), 吃(液體) 人和牛要吃所有的食物
68
動腦動手時間(2) 考慮一商店買賣系統 商店有貨品: 執行下列動作: 輸出: 湯瑪士:進貨50,單價290 培西:進貨40,單價290
哈諾:進貨20,單價290 執行下列動作: 賣(湯瑪士, 10) 賣(培西, 5) 特價(哈諾, 190) 賣(湯瑪士,60) 賣(哈諾, 10) 輸出: 每次賣東西後,都要針對該筆交易產生帳單 每次賣東西後,要顯示現在存貨 每次有更新,也要顯示狀況 最後,顯示庫存及單價
69
abstract class 食物_ex1 { String food_name; abstract void 吃的方式(); } class 液體_ex1 extends 食物_ex1 液體_ex1(String drink_name) food_name = drink_name; void 吃的方式() System.out.println("喝的"); class 固體_ex1 extends 食物_ex1 固體_ex1(String food) food_name = food; System.out.println("嚼的");
70
abstract class 動物_ex1 { String kind; abstract void 吃(食物_ex1 a); } class 人_ex1 extends 動物_ex1 人_ex1() kind = "人"; void 吃(食物_ex1 a) if (a instanceof 液體_ex1) System.out.print(a.food_name + "是用杯子"); a.吃的方式(); else System.out.print(a.food_name + "是用牙齒"); class 牛_ex1 extends 動物_ex1 牛_ex1() kind = "牛"; System.out.print(a.food_name + "是用舌頭"); System.out.print(a.food_name + "是用臼齒");
71
class Ex05_01 { public static void main(String [] args) 食物_ex1 x[] = {new 液體_ex1("珍珠奶茶"), new 固體_ex1("漢堡"), new 液體_ex1("水"), new 固體_ex1("草")}; 動物_ex1 y[] = {new 牛_ex1(), new 人_ex1()}; int i, j; for(i= 0; i<2; i++) System.out.println("== " + y[i].kind + " =="); for(j = 0; j < 4; j++) y[i].吃(x[j]); }
72
單一繼承 vs 多重繼承(1/2) Java的繼承是屬於單一繼承,C++的繼承是屬於多重繼承 多重繼承是指:指一個類別能夠繼承多個父類別
在許多時候多重繼承的性質是相當有用。 在Java,多重繼承的性質交給介面。
73
單一繼承 vs 多重繼承(2/2) 多重繼承的性質很有用,現實環境中,處處是多重繼承,想想以下情境:
你有一隻手機,它有PDA和GPS的功能,有一天,ToTo跟你借GPS 如果1:你怕ToTo弄壞了,他的媽媽又不會賠,這時,你可以採用『單一繼承』的說法, “不好意思,我有行動電話” 如果2:你不怕ToTo弄壞,因為他弄壞了,你就可以順理成章的成為他的小童星經紀人,好好利用他大賺一筆;則,你可以採用『多重繼承』的說法, “我有一隻手機,它有GPS的功能,借給你”
74
動動小手時間(1) 請繪出上一頁的行動電話的繼承圖
75
介面(1/2) 介面中定義的方法就像是飲料販賣機上的按鈕
76
介面(2/2) 介面(Interface)是在類別繼承架構中定義類別行為,內含常數和方法宣告,但是並沒有實作程式碼
77
介面的定義與實作(1/3) 定義介面的語法: 介面定義的例子: 修飾字 interface 介面名稱 { //靜態常數定義 //抽象方法宣告
} 介面定義的例子: interface MyInterface int i=2; //已預設使用 public、final、static void m(); //已預設使用 public、abstract
78
介面的定義與實作(2/3) 實作介面的類別定義語法: 修飾字 class 類別名稱 implements 介面名稱 {
//包含實作方法的敘述 }
79
介面的定義與實作(3/3) 介面多重繼承的語法: 類別實作多個介面的語法:
interface 子介面 extends 父介面一, 父介面二, ... { //新增的靜態常數及抽象方法 } 類別實作多個介面的語法: class 類別名稱 implements 介面一, 介面二, ... //類別主體敘述
80
範例1:宣告與使用介面(1/4) UML類別圖,如下圖所示:
81
範例1:宣告與使用介面(2/4) AreaInterface介面,如下所示: interface AreaInterface {
final double PI = ; void area(); }
82
範例1:宣告與使用介面(3/4) 接著Circle類別可以實作這個介面,如下所示:
class Circle extends Shape implements AreaInterface { ……… public void area() { System.out.println("X座標: " + x); System.out.println("Y座標: " + y); System.out.println("圓半徑: " + r); System.out.println("圓面積: " + PI*r*r); }
83
範例1:宣告與使用介面(4/4) abstract class Shape0601 { public double x;
public double y; } interface AreaInterface0601 { final double PI = ; void area(); class Circle0601 extends Shape0601 implements AreaInterface0601 { public double r; public Circle0601(double x, double y, double r) { this.x = x; this.y = y; this.r = r; public void area() { System.out.println("X座標: " + x); System.out.println("Y座標: " + y); System.out.println("圓半徑: " + r); System.out.println("圓面積: " + PI*r*r); class Ch06_01 { public static void main(String [] args) { Circle0601 c = new Circle0601(5.0, 5.0, 8.0); c.area(); System.out.println("PI常數: " + AreaInterface0601.PI); System.out.println("PI常數(以物件方式): " + c.PI); }
84
介面也是物件的型別 當物件所屬之類別在定義時實作某個介面,則此物件也「屬於」該介面型別的物件。意即,介面也是物件的型別。
若某個物件,其所屬之類別沒有實作介面,卻定義了介面宣告的方法時,該物件還是不屬於介面型別。 介面是物件的型別,所以介面也可以為陣列的基底型別,而形成異質集合。
85
介面的多重繼承 介面和介面之間也可以有繼承的關係,而且可以有多重繼承的關係
不可以有靜態常數的重複繼承。如果不同父介面中定義了同名的常數,則子介面型別的物件不可以使用該常數,以免發生曖昧不明的狀況
86
範例2:介面的多重繼承(1/3) 實線為繼承(extends),虛線為實作介面(implements)
87
範例2:介面的多重繼承(2/3) 請先練習一下功力 Ch06_02.java
88
範例2:介面的多重繼承(3/3) class Ch06_02 {
public static void main(String [] args) CCF a = new CCF(); a.m1(); a.m3(); a.m4(); a.m5(); } abstract class CCE String name = "CCE"; abstract void m1(); void m2() System.out.println("我在CCE的m2啦!"); interface IIA String name = "IIA"; void m3(); void m5(); interface IIB String name = "IIB"; interface IIC extends IIA, IIB String name = "IIC"; interface IID String name = "IID"; void m4(); class CCF extends CCE implements IIC, IID { String name = "CCF"; void m1() System.out.println("我在CCF的m1!"); m2(); } public void m3() System.out.println("我在CCF的m3!"); public void m4() System.out.println("我在CCF的m4!"); public void m5() System.out.println("我在CCF的m5!"); }請先練習一下功力
89
介面vs抽象類別(1/3) 介面和抽象類別的相似之處: 不能直接使用介面或抽象類別建立物件 介面與抽象類別都可以宣告抽象方法。
90
介面vs抽象類別(2/3) 介面(Interface)是在類別繼承架構中定義類別行為,內含常數和方法宣告,但是並沒有實作程式碼,它和抽象類別的差異,如下所示: 抽象類別的方法可能只有宣告,但是仍然可以擁有一般方法,介面的方法都只有宣告,而且一定沒有實作的程式碼。 介面不屬於類別的繼承架構,就算亳無關係的類別也一樣可以實作同一個介面。 類別只能繼承一個抽象類別,但是可以同時實作多個介面。
91
介面vs抽象類別(3/3) 介面和抽象類別的相異之處:
介面內的方法皆為 public 和 abstract 方法。抽象類別的抽象方法存取修飾字不限為 public。 介面內的屬性皆預設為public、static及final宣告,必須指定其值。抽象類別中的屬性則沒有限定 介面之間可以有多重繼承。抽象類別和其它類別之間只能有單一繼承 介面的目的是制訂整組訊息接收器的規格,模擬類別的多重繼承。抽象類別的目的則是制訂部份物件的規格,並制訂部份訊息接收器的規格,為多型做準備
92
大腦、小手動一動(2) 請設計兩種類別: 珍珠奶茶 奶茶珍珠 兩個物件分屬這兩類別
Similar presentations