Ch06 抽象類別和多形 物件導向程式設計(2).

Slides:



Advertisements
Similar presentations
单元二:面向对象程序设计 任务二:借书卡程序设计.
Advertisements

第三讲 面向对象(上).
3.2 Java的类 Java 类库的概念 语言规则——程序的书写规范 Java语言 类库——已有的有特定功能的Java程序模块
JAVA 编 程 技 术 主编 贾振华 2010年1月.
第一單元 建立java 程式.
大葉大學 指導教授: 黃鈴玲 學生: 林慶南(工業工程與科技管理所)
四資二甲 第三週作業 物件導向程式設計.
面向对象的程序设计(一).
南京理工大学 第2章 Java基本语法 本章我们将学习Java编程语言的基本语法,包括变量、操作符、表达式、语句、字符串、数组、控制流以及如何使用帮助文档。 使用下面的编程框架: public class Test{ public static void main(String []args){ //以下添加测试代码.
第一章 面向对象程序设计.
Ch03 物件導向程式設計_物件與類別 JAVA 程式設計入門(II).
第二章 JAVA语言基础.
類別的繼承-一般關係: 繼承是宣告的類別繼承現存類別的部份或全部的成員資料和方法 , 新增額外的成員資料和方法或覆寫和隱藏繼承類別的方法
Ch07 介面與多重繼承 物件導向程式設計(II).
第三章 控制结构.
Ch08 巢狀類別 物件導向程式設計(II).
2.1 基本資料型別 2.2 變數 2.3 運算式與運算子 2.4 輸出與輸入資料 2.5 資料型別轉換 2.6 實例
Ch03 類別與物件 物件導向系統分析與設計.
LINQ 建國科技大學 資管系 饒瑞佶.
Java簡介.
JAVA 程式設計與資料結構 第七章 繼承與Interface.
Ch05 繼承 Java程式設計入門(2).
程序與函數的類別方法 目的:模組化程式設計 方法:由上而下設計 注意事項:(1)獨立性 (2)結合問題 (3)子問題間的溝通.
第六章 类的扩展与继承.
Java 程式設計 講師:FrankLin.
Ch02 類別、物件及屬性 物件導向程式設計(II).
Ch03 方法 物件導向程式設計(II).
Ch10 類別與物件-方法 Java程式設計(2).
程式設計實作.
類別(class) 類別class與物件object.
Java程序设计 第9章 继承和多态.
程式設計(二) 進階類別 郭文真 Sabrina Kuo.
Ch01 物件與類別複習 物件導向系統實務.
類別的繼承 Vehicle Car.
第9讲 Java的继承与多态(一) 类的继承 子类的创建 方法覆盖.
Java 程式設計 講師:FrankLin.
2019/1/16 Java语言程序设计-类与对象 教师:段鹏飞.
JAVA 程式設計與資料結構 第四章 陣列、字串與數學物件.
Ch02-基礎語法.
C/C++/Java 哪些值不是头等程序对象
第一單元 建立java 程式.
* 單元:電腦與問題解決 主題:Java物件導向程式設計-類別與物件 台南縣國立善化高中 蕭嘉民 老師
辅导课程八.
JAVA 编 程 技 术 主编 贾振华 2010年1月.
第 19 章 XML記憶體執行模式.
物件導向系統分析與設計 CH04 物件導向開發方法.
Ch09 物件導向技術導論(二) Java程式設計(2).
第二章 Java基本语法 讲师:复凡.
Java程式初體驗大綱 大綱 在學程式之前及本書常用名詞解釋 Hello Java!程式 在Dos下編譯、執行程式
Class & Object 靜宜大學資工系 蔡奇偉副教授 ©2011.
第二章 Java语法基础.
陣列與結構.
龍老師我不會Debug QQ.
12 虛擬函數 12.1 多載與超載 12-2 多載函數 12-2 超載函數 虛擬函數 12-6 同名異式 12-7
第二章 Java基本语法 讲师:复凡.
第6單元 6-1 類別的繼承 (Class Inheritance) 6-2 抽象類別 (Abstract Class)
辅导课程十二.
第四章 陣列、指標與參考 4-1 物件陣列 4-2 使用物件指標 4-3 this指標 4-4 new 與 delete
PPT注意事项: 当前PPT课件文件必须和提供的源代码文件夹“代码”在同一目录中即不要移动文件夹“代码”的默认位置。
JAVA 程式設計與資料結構 第三章 物件的設計.
第2章 Java语言基础.
對於成員(member)存取權的限制 成員的資料被毫無限制的存取,任誰都可以指定任意值給成員,Java語言為了防止這種現象的產生,規定:有一種成員的資料不能任由類別外部的任何人隨意存取。
判斷(選擇性敘述) if if else else if 條件運算子.
第二章 Java基础语法 北京传智播客教育
輸出執行結果到螢幕上 如果要將執行結果的文字和數值都「輸出」到電腦螢幕時,程式要怎麼寫? class 類別名稱 {
第二章 Java基本语法 讲师:复凡.
第6章 继承和多态 伍孝金
Summary
方法(Method) 函數.
InputStreamReader Console Scanner
Presentation transcript:

Ch06 抽象類別和多形 物件導向程式設計(2)

方法的覆蓋(1/4) 子類別的重新定義物件方法稱為方法的覆蓋(Overriding)。 方法覆蓋時,下列各項都必須和父類別定義的方法相同: 方法的回傳型別。 方法名稱。 形式參數列中的型別及順序。 如果子類別定義的方法和父類別定義的方法同名,但參數不同時,只能算是一種多載(overloading)

方法的覆蓋(2/4) 覆蓋的原理:先碰到子類別定義之成員

方法的覆蓋(3/4) 方法覆蓋的主要用意是「修改原有功能的實作」。 使用 final 宣告的父類別之物件方法不能被覆蓋。 靜態方法無法使用覆蓋(沒有覆蓋的特性)。 覆蓋舊方法時,新定義的方法可以透過 super 參照呼叫舊方法。

方法的覆蓋(4/4) 方法覆蓋要注意下列幾點: 方法覆蓋時,沒有領域不同的區別,所有被覆蓋的方法一律打入冷宮。 回傳型別必須相同。 不能縮減方法的存取權限 丟出的例外型別必須相同 方法覆蓋時,沒有領域不同的區別,所有被覆蓋的方法一律打入冷宮。

範例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; }

範例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; }

範例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(); }

抽象類別(1/3) 類別定義中,只要有一個方法(或以上)定義為抽象方法(abstract method),則該類別為抽象類別(abstract class)。 抽象方法並沒有定義方法的主體(沒有實作) 無法利用抽象類別建立物件。 抽象類別的用處是當作父類別,讓子類別繼承。 子類別必須將父類別中的抽象方法實作出來,才能建立物件。

抽象類別(2/3) 抽象類別的定義語法: 某個類別的主體內,宣告了抽象方法,則該類別必須宣告為抽象類別。 修飾字 abstract class 類別名稱 { //屬性宣告 修飾字 abstract 型別 方法名稱(參數列); //其它方法定義 } 某個類別的主體內,宣告了抽象方法,則該類別必須宣告為抽象類別。 抽象類別雖然不能用以建立物件,但是可以當作物件的型別,用來宣告參照變數。 抽象類別的子類別若不完全實作抽象方法,則依然是抽象類別。

抽象類別(3/3) 使用抽象類別的用意,主要是「制定固定的訊息接收管道,但不把焦點放在訊息的處理上」。 抽象類別和一般類別一樣,都可以定義建構子,只是不能直接以抽象類別的建構子建立物件。 抽象方法的目的就是為了讓子類別實作,所以abstract 不能同時和 final、static 或 private 一起使用。

多型(polymorphism) 不論參照的型別為何,呼叫方法時,呼叫最新的覆蓋方法。 多型指的是「使用相同的訊息呼叫,可以進行不同的功能操作」。 動態結合(dynamic binding):當某個物件方法,接收傳入的A類別之物件時,該方法無法得知傳入的是A類別的物件,或A之延伸類別的物件,直到執行時才會知道,也才能知道要呼叫的是哪個方法。

多型(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

多型(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

多型(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; }

物件的型別轉換 子類別物件也屬於父類別物件 小紅是一條魚。 小紅是一隻脊椎動物。 小紅是一隻動物。

範例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

物件的型別轉換- 異質集合 相同類別的物件集合稱為同質集合(homogenous collections)。 不同類別的物件集合稱為異質集合(heterogeneous collections)。 基本型別的陣列為同質集合。 當父類別型別的參照陣列之元素分別指向不同的子類別物件時,此參照陣列稱為異質集合。 異質集合建立在父類別型別參照變數可以指向子類別物件的原理上。

物件的型別轉換- 異質集合的物件陣列 異質集合的物件陣列

範例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); }

物件的強制型別轉換(1/3) 物件型別轉換,其實是針對指向物件的參照變數,而不是針對物件實體。物件實體只要被建立,其佔用的記憶體位置及大小都不會被變更。 物件的強制型別轉換之語法 (目的類別)物件參照變數 物件參照變數所指向的物件實體,必須是目的類別的物件實體,或是其子類別的物件實體。

物件的強制型別轉換(2/3) 子類別物件轉換成父類別物件

物件的強制型別轉換(3/3) 父類別物件不具備子類別定義之成員,無法轉換成子類別物件。

instanceof運算子 instanceof運算式會得到一個布林值,若物件名稱所指向的物件實體屬於欲判斷的類別則回傳true;反之,回傳false。 物件名稱 instanceof 類別名稱 物件名稱所屬的參照型別必須和類別名稱有繼承關係,否則會發生錯誤。 instanceof的優先權和關係運算子的 <、>、<=、>= 相同,它們的運算結果都是布林值。

動腦動手時間(1) 請以範例4,5,6,7,8為參考 建立一個程式: 人和牛要吃所有的食物 食物類別:食物名稱 動物類別:吃() 液體類別 固體類別 動物類別:吃() 人類別:吃(固體), 吃(液體) 牛類別:吃(固體), 吃(液體) 人和牛要吃所有的食物

動腦動手時間(2) 考慮一商店買賣系統 商店有貨品: 執行下列動作: 輸出: 湯瑪士:進貨50,單價290 培西:進貨40,單價290 哈諾:進貨20,單價290 執行下列動作: 賣(湯瑪士, 10) 賣(培西, 5) 特價(哈諾, 190) 賣(湯瑪士,60) 賣(哈諾, 10) 輸出: 每次賣東西後,都要針對該筆交易產生帳單 每次賣東西後,要顯示現在存貨 每次有更新,也要顯示狀況 最後,顯示庫存及單價

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("嚼的");

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 + "是用臼齒");

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]); }

薪資系統(1/8) abstract class 員工 { String 姓名; String 工作部門; int 薪水; 員工(String name, String dept) 姓名 = name; 工作部門 = dept; } void print薪資單() System.out.println("薪資單"); System.out.println("姓名: " + 姓名 + " 工作部門: " + 工作部門); abstract void 薪水();

薪資系統(2/8) abstract class 正職 extends 員工 { int 月薪; 正職(String name, String dept, int salary) super(name, dept); 月薪 = salary; } void print薪資單() super.print薪資單(); System.out.println("月薪: " + 月薪);

薪資系統(3/8) abstract class 兼職 extends 員工 { int 工資; 兼職(String name, String dept) super(name, dept); } void print薪資單() super.print薪資單(); System.out.println("工資: " + 工資);

薪資系統(4/8) class 主管 extends 正職 { 主管(String name, String dept, int salary) super(name, dept, salary); } void print薪資單() super.print薪資單(); System.out.println("總計: " + 薪水); void 薪水() 薪水 = 月薪;

薪資系統(5/8) class 一般員工 extends 正職 { int 加班費; 一般員工(String name, String dept, int salary, int h) super(name, dept, salary); 加班費 = h * 100; } void print薪資單() super.print薪資單(); System.out.println("加班費: " + 加班費); System.out.println("總計: " + 薪水); void 薪水() 薪水 = 月薪 + 加班費;

薪資系統(6/8) class 業務員 extends 正職 { int 業績獎金; 業務員(String name, String dept, int salary, int 業績) super(name, dept, salary); 業績獎金 = 業績 * 5 / 100; } void print薪資單() super.print薪資單(); System.out.println("業績獎金: " + 業績獎金); System.out.println("總計: " + 薪水); void 薪水() 薪水 = 月薪 + 業績獎金;

薪資系統(7/8) class 計件工作人員 extends 兼職 { 計件工作人員(String name, String dept, int 件數) super(name, dept); 工資 = 件數 * 10; } void print薪資單() super.print薪資單(); System.out.println("總計: " + 薪水); void 薪水() 薪水 = 工資;

薪資系統(8/8) class 計時工作人員 extends 兼職 { 計時工作人員(String name, String dept, int h) super(name, dept); 工資 = h * 100; } void print薪資單() super.print薪資單(); System.out.println("總計: " + 薪水); void 薪水() 薪水 = 工資;

JAVA程式設計 以[大富翁]為例

V8:抽象類別 -以玩家可以有不同個性為例 學習抽象類別 學習抽象方法 學習異質集合

//土地類別沒有更動 class 土地 { String 地名; int 過路費 = 20; int 地價; 玩家 地主; { this.地名 = 地名; } 土地(String name, int price) { 地名 = name; 地價 = price; void 登記土地所有權人(玩家 買地人) { if(買地人.錢 >= 地價) { //有錢可以買地 買地人.錢 -= 地價; 地主 = 買地人; System.out.println(買地人.名字 + "買了" + 地名); else System.out.println(買地人.名字 + "沒有買地"); return;

//土地2多加一個[登記土地所有權人]的方法,只是為了連結到父類別的[登記土地所有權人]方法 class 土地2 extends 土地 { int [] 過路費 = new int[6]; int 房子數 = 0; 土地2(String 地名) { super(地名); for(int i = 0; i < 過路費.length; i++) 過路費[i] = 20 + i*10; } 土地2(String name, int price) { super(name); 地價 = price; void 登記土地所有權人(玩家 買地人) { super.登記土地所有權人(買地人);

//將原來的類別改成抽象類別,並加上抽象方法[購地策略] abstract class 玩家 { String 名字; int 錢 = 2000; int 位置 = 0; 玩家(String name) { 名字 = name; } void 前進() { 位置 += ((int)(Math.random()*11) + 2); if (位置 >= 40) { 位置 -= 40; 錢 += 1000; return; void 付過路費(土地2 路過此地) { 錢 -= 路過此地.過路費[路過此地.房子數]; 路過此地.地主.錢 += 路過此地.過路費[路過此地.房子數]; System.out.println(名字 + "要付給 " + 路過此地.地名 + " 的地主 " +路過此地.地主.名字 + " " + 路過此地.過路費[路過此地.房子數] + " 元"); abstract void 購地策略(土地2 l);

//建立兩個子類別,並實作父類別的抽象方法[購地策略] class 我就是要買 extends 玩家 { 我就是要買(String name) { super(name); } void 購地策略(土地2 l) { l.登記土地所有權人(this); class 打死不買 extends 玩家 { 打死不買(String name) { System.out.println(名字 + "是打死不買,所以不買就是不買");

//在主程式的部份,利用異質陣列,只需在配置空間時,宣告為[打死不買]和[我就是要買]的不同類別物件 class 大富翁 { public static void main(String [] args) {String [] 土地名 = {"中華民國", "日本", "韓國", "菲律賓", "馬來西亞", "越南", "泰國", "印度", "伊拉克", "伊朗", "沙烏地阿拉伯", "土耳其", "以色列", "蘇俄", "波蘭", "德國", "奧地利", "瑞士", "法國", "比利時", "荷蘭", "英國", "芬蘭", "瑞典", "丹麥", "希臘", "義大利", "西班牙", "葡萄牙", "埃及", "摩洛哥", "南非", "加拿大", "美國", "墨西哥", "宏都拉斯", "尼加拉瓜", "古巴", "巴拿馬", "巴西"} ; String [] PN = {"喜羊羊", "美羊羊", "小灰灰", "灰太狼"}; 土地2 L [] = new 土地2[40]; for (int i = 0; i < L.length; i++) { if(i/2 * 2 == i) L[i] = new 土地2(土地名[i], i*20); else L[i] = new 土地2(土地名[i]); // L[i].地名 = 土地名[i]; System.out.println(L[i].地名 + " 地價是 " + L[i].地價); }

//異質陣列 玩家 P [] = new 玩家[4]; for (int i = 0; i < P //異質陣列 玩家 P [] = new 玩家[4]; for (int i = 0; i < P.length-2; i++) { P[i] = new 打死不買(PN[i]); } for(int i = 2; i < P.length; i++) { P[i] = new 我就是要買(PN[i]); //P[0].名字 = "喜羊羊"; //P[1].名字 = "美羊羊"; //P[2].名字 = "小灰灰"; //P[3].名字 = "灰太狼"; for(int j = 1; j <= 5; j++) { System.out.println("第 " + j + " 輪 "); /* System.out.println("目前土地狀態"); for (int k = 0; k < L.length; k++) if( L[k].地主 != null) System.out.println(L[k].地名 + " 地主是 " + L[k].地主.名字); else System.out.println(L[k].地名); */

for(int i = 0; i < P. length; i++) { P[i]. 前進(); System. out for(int i = 0; i < P.length; i++) { P[i].前進(); System.out.println(P[i].名字 + " 在 " + L[(P[i].位置)].地名 + ", 現在有錢" +P[i].錢); if(L[P[i].位置].地主 == null) { //買地 P[i].購地策略(L[P[i].位置]); // System.out.println(L[P[i].位置].地名 + "目前尚未售出"); // L[P[i].位置].登記土地所有權人(P[i]); } else { //付過路費 if (L[P[i].位置].地主 != P[i]) P[i].付過路費(L[P[i].位置]);