15. }
【程式 Line.java】
:
Line 類別繼承至 Dot 類別,因此在 Line 類別中將可以呼叫父類別(Dot 類別)所提供的方
法,在 drawLine()方法中,利用重覆的呼叫 Dot 類別的 drawDot()方法繪製出我們需要長度的
線條於螢幕上,其中 offset 傳入參數代表的是線條的起始位置,length 傳入參數代表的是線
條的長度。
//Line.java
//繪製一條線於螢幕上
//繼承至Dot
public class Line extends Dot{//繼承Dot類別
int offset=0;
//設定每條線的空隔偏移
public void setInterval(int value){
int
offset=value;
}
//繪製線於螢幕上
public void drawLine(int offset,int length){
int int
for int i=1;i<=offset;i++){
for(int
System.out.print(" ");//依偏移量繪製空格
}
for int i=1;i<=length;i++){
for(int
drawDot();//呼叫父類別的drawDot方法畫點
}
System.out.println("");//斷行
}
}
【程式 Shape.java】
:
Shape 類別繼承至 Line 類別,因此在 Shape 類別中可以直接呼叫父類別(Line 類別)所提
供的方法,在這 drawTriangle()方法中我們依三角型的圖形需求向 Line 類別呼叫繪圖多條不
同長度的與起始位置的線條,最後這些線條將會排例成一個正三角型。
61
16. //Shape.java
//繪製圖型於螢幕上
public class Shape extends Line{
//繪製三角型的方法
public void drawTriangle(int height){
int
int lenght=1;//線的長度
//依照要求高度繪製圖型
for int i=1;i<=height;i++){
for(int
//呼叫父類別的drawLine方法
drawLine((height-i),lenght);
lenght=lenght+2;//線的長度加二
}
}
}
【程式 DrawMain.java】
:
DrawMain 為本範例的主程式,在程式進入點 main 方法裡,首先將 Shape 類別實作成二個
物件,並分別存放於 triangleA 與 triangleB 變入中,接著我們為這兩個物件分別設定二個不
同的輸出字元與高度。到這裡不知讀者是否還記得前一節所介紹的類別與物件的關係,在此範
例中我們利用同樣的 Shape 類別實作成兩個物件,隨後它們分別擁有個自的資料成員,因此到
最後的輸出結果,將會有兩個截然不同的表現方式。讀者可以再重新的回想思考一下類別與物
件之間的關係,相信應該很快就能有所領悟。
//DrawMain.java
//主程式
public class DrawMain {
public static void main(String args[]){
//取得Shape物件,並指定至triangleA變數中
Shape triangleA =new Shape();
new
//取得Shape物件
Shape triangleC =new Shape();
new
//設定圖型樣式為字元'A'
triangleA.setStyle('A');
//繪製高度為10的三角型
62
19. A objectA = new A();
B objectB = new A();
由於 A 類別是繼承至 B 類別,所以我們可以將 A 物件轉型成為 B 物件型態,若讀著還記得先前
章節所介紹的轉型方式,該還記得由小資料型別轉大資料型別並不會造成資料流失因此可以自
動轉型,但由大資料型別轉小資料型別可就得非得利用強制轉不可,同樣的,若我們將上式改
寫成:
A objectaA=new B();
將發生編譯錯誤的情況,原因是 B 類別只是被 A 類別繼承,所以 B 類別並無法得知 A 類別內
部所提供的資料與方法,聰明的讀者這時一定想到若利用強制轉型方式便可以順利的轉型過
去,但這樣做將會發生執行時期錯誤(Run time error),這將會讓你的程式隱藏著不可預期的
錯誤(因為是由 B 物件並不認得 A 物件的內容)
。
【多型範例程式】
//多型範例
//Polymorphism.java
//SuperClass為父類別
class SuperClass{
public void superMethod1(){
System.out.println("SuperClass");
}
public void superMethod2(){
System.out.println("SuperClass");
}
}
//Polymorphism為子類別,同時也是主程式
public class BaseClass extends SuperClass{
//覆寫掉SuperClass類別的superMethod1()方法
public void superMethod1(){
System.out.println("BaseClass");
}
//子類別式所提供的方法
public void baseMethod(){
System.out.println("BaseClass");
}
65
26. 或許讀者初次使用介面的觀念一時之間會難以適應,但只要有耐心養成使用介面撰寫程式
的良好習慣,相信很快的就可以體驗到程式再利用所帶來的好處。
首先讓我們先看到介面的語法結構:
public interface 介面名稱{
final 常數型態宣告 常數名稱;
public void 抽像方法名稱();
}
介面的宣告與類別相當類似,類別使用的是 class 關鍵字,而介面使用的則是 interface,
關鍵字之後接的是介面的名稱,這裡與類別命名規則一樣,介面名稱必須於程式檔案名稱相
同。介面裡所宣告的所有變數都將被自動冠上 final 關鍵字,因此介面中的變數皆為常數不允
許被更動。介面中的方法皆為抽像的方法,並不會進行方法的實作,所以介面中所有的抽像方
法宣告都是以雙引號 ; 做為結尾,例如:
public void test();
public void run();
在介面中並不需要利用 abstract 修飾字,所有在介面中所宣告的方法會自動被視為抽像的,
以下為一個簡單的介面宣告範例:
//Book.java 介面範例:
public interface Book {
//設定書本資訊的介面
public void setInfo(String name,String author, int price);
//取得書本資訊的介面
public String getInfo();
}
Book 為一個關於書藉資料的介面,透過介面將一般書藉常見的資訊抽離出來,像是作者書本
名稱、作者名稱、價格,任何只要有實作 Book 介面的程式就必須實介面中所宣告的方法。在
72
27. 撰寫完介面之後,必須於類別中使用 implements 關鍵字來宣告此類別所實作的介面,另外
implements 關鍵字後可以同時宣告多個介面,每個不同介面名稱之間需使用逗號方開,語法
使用方式如下:
修飾詞 class 類別名 implements 介面名1, 介面名2, 介面名3{
}
底下為一個完整的介面範例程式
【介面範例程式】
//BookOne.java 實作Book介面
public class BookOne implements Book{//實作Book介面
String bookName;
String authorName;
int bookPrice;
//實作取得書本資訊介面
public String getInfo() {
String info="Book Name="+bookName+
" Author Name="+authorName+" Price="+bookPrice;
return info;
}
//實作設定書本資訊介面
public void setInfo(String name, String author, int price) {
bookName=name;
authorName=author;
bookPrice=price;
}
}
//BookTwo.java 實作Book介面
public class BookTwo implements Book{//實作Book介面
String bookName;
String authorName;
int bookPrice;
//實作取得書本資訊介面
73
28. public String getInfo() {
String bookInfo="Book NAME t Author Name t pricen"+
bookName+" tt "+authorName+" tt "+bookPrice;
return bookInfo;
}
//實作設定書本資訊介面
public void setInfo(String name, String author, int price) {
bookName=name;
authorName=author;
//打八折
int)(price*0.8);
bookPrice=(int
int
}
}
//BookMain.java 介面應用範例主程式
public class BookMain {
public static void main(String args[]){
//取得BookOne物件,並轉型為Book介面
Book book1=new BookOne();
new
//利用setInfo介面設定書本資訊
book1.setInfo("LatteBox", "Jarey", 100);
//取得BookTwo物件,並轉型為Book介面
Book book2=new BookTwo();
new
//利用setInfo介面設定書本資訊
book2.setInfo("java", "tony", 200);
//利用getInfo介面取出書本資訊
System.out.println("nbook1的資訊為:");
System.out.println(book1.getInfo());
System.out.println("nbook2的資訊為:");
System.out.println(book2.getInfo());
}
}
【執行結果】
74
29. 圖 1-12 多型範例執行結果
在範例中,BookOne 與 BookTwo 為兩個不同的類別,BookTwo 在設定價格時,會自動將書
本的價格打八折,另外兩者在顯示書藉資訊格式也略有不同,但兩個類別都同時實作 Book 介
面,因此可以確定的是兩個類別一定會提供 setInfo 與 getIfno 這兩個函式。在主程式中
BookOne 與 BookTwo 物件雖然與 Book 無繼承的關係,但卻擁有界面實作的關係,所以可以自
動的轉型為 Book 介面型別(因為 Book 所提供的函式一定能於實作的類別中呼叫成功)
,隨後
的操作就都只認介面不認類別。利用介面可以不用費心去了解介面後面的實作方式為何,直接
可以透過介面所提供函式進行操作,就如同範例中 BookOne 與 BookTwo 兩個物件對於 Book 介
面實作的方式略有不同(如印出資訊的格式、與價格計算方式),但主程式中對於兩個物件的操
作方式卻都是相同的(同樣呼叫 setInfo 與 getInfo 函式)。讀者可以自行設計其它實作 Book
介面的類別,替換掉原本的 BookOne 或 BookTwo 類別,且無需更動到主程式中函式對於 Book
的操作方式,就能另程式有不同的風格展現,這也就是利用介面將程式函式架構從實作面抽離
的好處。
3.6 (抽像類別 Abstract class)
在介面中我們可以定義方法的名稱與傳入、傳出的型態,但不去實作當中的邏輯。抽像類別與
介面不同之處在於,抽像類別可以同時包含抽像的方法,與己實作的法方。在抽像類別中我們
可以同時定議許多的抽像方法 Abstract method(如同介面並實作其中的邏輯)
,但也可以包
含其他己經具有邏輯實作的方法。 簡單的說我們可以把抽像類別看成一個完成一半的程式,
另一半未完成的部份我們只明確定義了操的介面,實作部份則交由其他的類別去完成。我們將
75