“你好,阿米戈!我們有一個有趣的新話題。”

“今天真是話題多多的一天!”

“為什麼要謝你!”

“不客氣。”

“還記得我們引入 ChessItem 基類來簡化所有棋子類嗎?”

“是的。”

“現在假設每個棋子都有一個方法來處理在屏幕上渲染棋子。您調用該方法,棋子會在其當前坐標處自行繪製。將此方法移至基類中是否有幫助?”

“是的。” 在了解多態性之後,我將能夠為所有片段調用 render 方法,而不管它們是什麼類型。像這樣的東西:“

例如:
class ChessBoard
{
  public void drawAllChessItems()
  {
  //draw them regardless of their type.
  ArrayList <ChessItem> items = new ArrayList<ChessItem>();
  items.add(new King());
  items.add(new Queen());
  items.add(new Bishop());

  //draw them regardless of their type.
  for (ChessItem item: items)
  {
   item.draw();
  }
 }
}

“幹得好。完全正確。ChessItem 類本身的 draw 方法會做什麼?”

“我不知道。國際象棋沒有這樣的棋子。這意味著它沒有視覺表現。”

“準確地說。創建一個 ChessItem 對像沒有意義。沒有這樣的棋子。它只是一個抽象——我們為了方便而創建的類。這就是抽像在 OOP 中的工作方式:我們移動了所有重要的(共享的)將所有棋子)數據和方法放入一個基類中,但我們將它們的差異保留在對應於特定棋子的類中。”

Java 為此有一個特殊的類類型:抽像類。關於抽像類,需要記住以下三點。

1) 抽像類可以聲明方法而不實現它們。這樣的方法稱為抽象方法。

例如:
 public abstract class ChessItem
{
 public int x, y; //coordinates
 private int value; //the piece's "value"

 public int getValue() //an ordinary method, returns value
 {
   return value;
 }

 public abstract void draw(); //abstract method. There is no implementation.

}

2) 抽象方法用關鍵字abstract標記。

如果一個類只有一個抽象方法,那麼這個類也被標記為abstract

3) 不能創建抽像類的對象。試圖這樣做的代碼根本無法編譯。

Java代碼 描述
ChessItem item = new ChessItem();
item.draw();
此代碼無法編譯。
ChessItem item = new Queen();
item.draw();
但你可以做到這一點。

4)如果你的類繼承了一個抽像類,你需要覆蓋所有繼承的抽象方法,即你必須實現它們。否則,您的類也必須聲明為抽像類。如果該類甚至有一個未實現的方法直接在類中聲明或從父類繼承,則該類被認為是抽象的。

“但是為什麼這一切都是必要的?為什麼我們需要抽像類?難道不能使用普通類來代替嗎?除了抽象方法,我們不能只創建由左右大括號組成的空實現嗎?”

“你可以。但這些限制就像修飾符private。我們使用private修飾符來故意阻止對數據的直接訪問,以便其他程序員和他們的類使用我們的public方法。”

這同樣適用於抽像類。編寫該類的人不希望任何人創建該類的實例。相反,作者希望他或她的抽像類的抽象方法被繼承和覆蓋。

“我仍然不明白為什麼我們要以這種方式使我們的生活複雜化。”

“這個特性的優勢在大型項目中很明顯。你擁有的類越多,你就越需要清楚地劃分他們的角色。你會看到這樣做的優勢,很快。每個人都必須經歷這一點。”