1 / 87

抽象類別與介面

第 12 章. 抽象類別與介面. 本章重點. 12 - 1 抽象類別 (Abstract Class) 12 - 2 介面 ( Inter face) 12 - 3 介面的繼承 12 - 4 綜合演練. 12 - 1 抽象類別 (Abstract Class). 回頭看看上一章中提到多層的繼承時 , 所與的圖形類別範例 , 在 Shape 、 Circle 、 Cylinder 、 Rectangle 這幾個類別中 , Shape 這個類別其實並未被主程式用到 , 而其存在的目的只是為了讓整個繼承結構更完善。

Download Presentation

抽象類別與介面

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第 12 章 抽象類別與介面

  2. 本章重點 • 12 - 1 抽象類別 (Abstract Class) • 12 - 2 介面 ( Inter face) • 12 - 3 介面的繼承 • 12 - 4 綜合演練

  3. 12 - 1 抽象類別 (Abstract Class) • 回頭看看上一章中提到多層的繼承時, 所與的圖形類別範例, 在 Shape、Circle、Cylinder 、Rectangle 這幾個類別中, Shape 這個類別其實並未被主程式用到, 而其存在的目的只是為了讓整個繼承結構更完善。 • 實際上 Shape 只是一個抽象的概念, 程式中並不會有 Shape 的物件, 而只會使用它的衍生類別如 Circle、Rectangle 等, 來建立物件。因此, 我們需要一種方法, 可以讓類別的使用者知道, Shape 這個類別並不能用來產生物件。

  4. 抽象類別 (Abstract Class) • 12-1-1 甚麼是抽象類別? • 12-1-2 抽象方法 (Abstract Method) • 12-1-3 抽象類別、抽象方法與繼承關係

  5. 12-1-1 甚麼是抽象類別? • 為了解決上述的問題, Java 提供抽象類別 (Abstract Class)的機制, 其用途即是讓我們標註某個類別僅是抽象的概念, 不應該用以產生物件。只要在類別的名稱之前加上 abstract存取控制字符, 該類別就會成為抽象類別, Java編譯器將會禁止任何產生此物件的動作。舉例來說, 在上述的範例中, Shape 類別就很適合更改為抽象類別, 因為這此類別不代表具體的物件, 真正的物件必須由其子類別產生。因此, 程式就可以改成這樣:

  6. 甚麼是抽象類別? • 由於抽象類別不能建立物件, 因此只要程式中有任何地方想要建立抽象類別的物件, 在編譯時, 就會出現錯誤, 例如以下的範例:

  7. 甚麼是抽象類別?

  8. 甚麼是抽象類別? • 如上所示, 一旦在類別定義前加上 abstract 將其宣告為抽象類別後, 在程式中要建立該類別的物件就會被視為錯誤。

  9. 12-1-2 抽象方法(Abstract Method) • 同樣的道理, 在上一章所舉的計算地價的程式範例中, Land 類別也可視為是一個抽象的概念, 表示某種形狀的土地, 真正能用來計算地價時, 都是使用其子類別 Circle、Square 等所建立的物件。因此, Land 也是標註為抽象類別的好對象:

  10. 抽象方法 (Abstract Method) • 不過讓我們仔細思考一下, Land 這個抽象類別和前述圖形類別 Shape 有些微的不同。在 Shape 類別中所定義的建構方法或其它方法, 是其子類別所共同需要的且會實際呼叫使用的;可是在 Land 類別中, 其定義的 area() 方法, 本身並不執行任何動作, 它的存在只是為了確保所有 Land 的衍生類別都會有 area() 方法而已, 至於各衍生類別 area() 方法實際要進行什麼動作, 則是由各衍生類別自行依本身的特性定義之。

  11. 抽象方法 (Abstract Method) • 但是因為方法的定義一定要包含有主體區塊, 所以在 Land 類別中的 area() 方法就定義成很無聊的傳回 0。 • 在 Java 中, 對於這種性質的方法, 可以將之標註為抽象方法 (AbstractMethod) , 如此一來, 就只需要定義方法的名稱以及所需要的參數及傳回值的型別即可, 而不需要定義其主題區塊的內容。

  12. 抽象方法 (Abstract Method) • 標註的方法很簡單, 就和抽象類別的標註方式一樣, 只要在方法名稱之前加上abs t ract 存取控制字符即可。同樣以 Land 類別為例:

  13. 抽象方法 (Abstract Method)

  14. 抽象方法 (Abstract Method)

  15. 抽象方法 (Abstract Method)

  16. 抽象方法 (Abstract Method)

  17. 抽象方法 (Abstract Method)

  18. 抽象方法 (Abstract Method) • 第 2 行就是加上 abstract 標註的 area() 方法, 由於不需要定義其主體區塊,所以要記得在右括號之候補上一個分號 ( ; ),表示這個敘述的結束。 • 使用抽象方法時, 要特別注意, 擁有抽象方法的類別一定要標註為抽象類別。這道理很簡單, 抽象方法代表的意義是這個方法要到子類別才會真正實作, 既然如此, 就表示其所屬的類別並不完整, 自然就不應該拿來產生物件使用, 所以必須為抽象類別。

  19. 抽象方法 (Abstract Method) • 但是反過來說, 一個抽象類別卻未必要擁有抽象方法, 像是前面介紹的Shape 類別就未定義抽象方法。

  20. 12-1-3 抽象類別、抽象方法 與繼承關係 • 對於一個擁有抽象方法的抽象類別來說, 如果其子類別並沒有實作其中的所有抽象方法, 那麼這個子類別就自動變成抽象類別。例如:

  21. 抽象類別、抽象方法與繼承關係

  22. 抽象類別、抽象方法與繼承關係 • 由於 Child 並沒有實作繼承而來的 show() 抽象方法, 所以編譯的錯誤訊息就是說 Child 也必須是一個抽象類別。如果要正確編譯這個程式, 除了必須為 Child 類別加上 abstract 存取控制, 同時第 17 行也不能用它建立物件, 請參考以下的例子:

  23. 抽象類別、抽象方法與繼承關係

  24. 抽象類別、抽象方法與繼承關係

  25. 抽象類別、抽象方法與繼承關係 • 此範例修正了之前的錯誤, 除了在第 5 行將 Child 類別定義為 abstract (因為它沒有實作抽象方法 show()), 第 main() 方法中, 也改用有實作 show() 的Grandson 類別來建立物件, 因此可正常編譯執行。

  26. 12 - 2 介面 ( Inter face) • 前面提過, 撰寫物件導向程式的第一步, 就是分析出程式中需要哪些類別, 以及類別之間的繼承關係。不過就像我們在現實世界中所看到的, 許多『不同類』的事物, 其間又通常會具有一些相似的行為。舉例來說, 飛機和小鳥很顯然不會是同性質的類別, 而其飛的方式也不同, 但不可否認它們都具有會飛行的行為。

  27. 介面 ( Inter face) • 類似這樣的情況, 在設計程式時也會遇到:一些在繼承架構中明顯不同的類別, 它們卻有具有一些相似的行為 (特性), 造成設計類別時的困擾, 例如將明顯不同性質的類別 (例如飛機和鳥), 湊成在同一繼承架構下, 使得類別的繼承關係不合常理。因此為了不打亂原有的繼承架構, 我們可能要選擇分別在各自的類別中定義各自有的行為。 • 為了讓這樣的設計也能系統會, 不會造成不同性質的類別, 在實作它們應有的共通行為時造成遺漏或命名不一致, 在 Java 中特別提供了介面(Interface) 來描述這個共通的行為。

  28. 介面 ( Inter face) • 12-2-1 定義介面 • 12-2-2 介面的實作 • 12-2-3 介面中的成員變數

  29. Java 不支援多重繼承 • 有些物件導向程式語言會支援多重繼承 (Multiple Inheritance), 也就是讓單一類別同時繼承自多個父類別, 如此一來可解決上述不同性質類別有共通行為的問題。 • 不過多重繼承也會使語言複雜化, 而在第一章我們就提過『, 簡單』是 Java 語言的主要特色之一, 因此當初開發 Java 語言的小組就決定讓 Java 語言不支援多重繼承, 以保持其簡單學的特色。 • 雖然如此, Java 的實用性並不因此而減少, 需要使用到多重繼承的場合, 幾乎也都可透過 Java 的介面功能達成。

  30. 12-2-1 定義介面 • 由於介面代表的是一群共通的行為, 感覺上和類別好像有些類似之處, 但其實兩者具有相當的差異, 只是外觀上定義介面也是用大括號來描述此介面的方法, 而開頭要改用 interface 來表示要定義的是介面:

  31. 定義介面 • 由於類別是用以描述實際存在的物件, 而介面則僅是用以描述某種行為方式 (例如『會飛』這件事), 所以兩者本質上有許多差異, 以下是定義介面時要注意的重點: • 介面的命名也和類別一樣, 通常都是以首字母大寫的方式, 使得其在程式中容易被識別。有些人習慣在介面的名稱前加上一個大寫字母' I", 以特別標示這個名稱是個介面。

  32. 定義介面 • 在介面中只能定義方法的型別 (傳回值) 及參數型別, 不可定義方法本體(和抽象方法相同), 這些方法預設都會自動成為 public 的抽象方法, 請記得在右括號之後加上分號。 • 由於介面通常代表某種特性, 因此介面的名稱一般都是一個形容詞, 表示可以如何的意思, 例如可用 Flying 表示『會飛』的意思。

  33. 定義介面 • 舉例來說, 前一章最後我們舉了計算地價的範例, 要計算地價時, 當然要算出土地的面積, 然而計算面積這件事, 可能是很多類別需要的功能, 所以我們可以定義一個計算面積的介面:

  34. 定義介面 • 如前所述, 不可定義方法本體, 因為每種不同形體, 其面積的計算方式也都不同, 我們也無法預知有哪些類別需要計算面積, 此處 surfacing 介面只規定了計算面積的方式名稱為 area、沒有參數、但傳回值為 double 型別。 • 如前所述, 介面中的方法預設都是公開的抽象方法, 所以通常 public 、abstract 也都省略不寫。

  35. 12-2-2 介面的實作 • 定義好介面之後, 需要使用該介面的類別, 就必須實作該介面, 實作介面時, 必須在類別名稱之後, 使用implements保留字, 再加上要實作的介面名稱。此外, 前面提過, 介面中所定義的方法會自動成為抽象方法, 因此實作介面時就必須完全實作介面中的所有方法。

  36. 介面的實作

  37. 介面的實作 • 我們先用上一章 Shape 類別及 Circle 類別的繼承架構, 並讓 Circle 實作Surfacing 介面:

  38. 介面的實作

  39. 介面的實作

  40. 介面的實作 • 第 18 行的 Circle 類別定義, 先繼承了 Shape 類別再以 implements 保留字表示此類別要實作 Surfacing。因此 Circle 類別必須定義於 Surfacing 介面中宣告的 area() 方法, 所以在第 27 行定義了計算圓面積的 area() 方法。如果宣告了要實作某個介面, 但類別中未定義該介面所宣告的方法, 編譯時將會出現錯誤。 • 另外, 要記住介面所提供的方法都是 public, 因此實作介面時也要將之宣告為 public, 不可將之設為 protected 或 private, 如此也會造成編譯錯誤。

  41. 12-2-3 介面中的成員變數 • 介面也可以擁有成員變數, 不過在介面中宣告的成員會自動擁有 stati cpublic final的存取控制。換句話說, 在介面中僅能定義由所有實作該介面的類別所共享的常數。舉例來說, 在剛才的例子中, 將圓周率常數定義在介面中, 而實作該介面的類別, 亦可存取該常數:

  42. 介面中的成員變數

  43. 介面中的成員變數

  44. 介面中的成員變數

  45. 介面中的成員變數 • 在第 3 行於介面中定義了成員變數 PI, 並在第 28 行 Circle 類別的 area()方法用以計算圓面積。雖然定義 PI 時未加上任何存取控制字, 但如前述, 介面中的成員變數會自動成為 public static final, 所以在程式第 41 行也能如同存取類別 static 成員變數一般, 用介面名稱存取其值。

  46. 12 - 3 介面的繼承 • 介面之間也可以依據其相關性, 以繼承的方式來架構, 就像是在上一章中對於類別的分類一樣。不過介面的繼承與類別的繼承最大的差別, 就在於介面可以繼承多個父介面, 而類別無法繼承多個父類別。也正由於這樣的差異, 因而衍生出幾個必須注意的主題, 這些都要在這一小節中討論。

  47. 介面的繼承 • 12- 3 - 1 簡單的繼承 • 12- 3 - 2 介面的多重繼承 • 繼承多個同名的方法 • 繼承多個同名的成員變數 • 實作多重介面

  48. 12- 3 - 1 簡單的繼承 • 介面的繼承最簡單的形式就是使用 extends 保留字從指定的介面延伸,例如:

  49. 簡單的繼承

  50. 簡單的繼承 • 第 7 行中就宣告了一個繼承自介面 P 的介面 C。由於有繼承關係, 所以介面 C 的內容除了自己所定義的 getI() 方法之外, 也繼承了由 P 而來的成員變數 i 以及 show() 方法。因此, 在第 11 行實作介面 C 時, 就必須實作getI() 以及 show() 方法。

More Related