Java抽象類和介面的區別

2020-07-16 10:05:20
前面《Java介面》一節中提到介面是一種特殊的抽象類,介面和抽象類的淵源頗深,有很大的相似之處,所以在選擇使用誰的問題上很容易迷糊。本節我們先整理一下 Java 中抽象類和介面的特點,再分析它們具有的相同點、不同點和使用場景。

1)抽象類

在 Java 中,被關鍵字 abstract 修飾的類稱為抽象類;被 abstract 修飾的方法稱為抽象方法,抽象方法只有方法宣告沒有方法體。

抽象類有以下幾個特點:
  1. 抽象類不能被範例化,只能被繼承。
  2. 包含抽象方法的類一定是抽象類,但抽象類不一定包含抽象方法(抽象類可以包含普通方法)。
  3. 抽象方法的許可權修飾符只能為 public、protected 或 default,預設情況下為 public。
  4. 一個類繼承於一個抽象類,則子類必須實現抽象類的抽象方法,如果子類沒有實現父類別的抽象方法,那子類必須定義為抽象類。
  5. 抽象類可以包含屬性、方法、構造方法,但構造方法不能用來範例化物件,只能被子類呼叫。

2)介面

介面可以看成是一種特殊的類,只能用 interface 關鍵字修飾。

Java 中的介面具有以下幾個特點:
  1. 介面中可以包含變數和方法,變數被隱式指定為 public static final,方法被隱式指定為 public abstract(JDK 1.8 之前)。
  2. 介面支援多繼承,即一個介面可以繼承(extends)多個介面,間接解決了 Java 中類不能多繼承的問題。
  3. 一個類可以同時實現多個介面,一個類實現某個介面則必須實現該介面中的抽象方法,否則該類必須被定義為抽象類。

3)抽象類和介面的區別

介面和抽象類很像,它們都具有如下特徵。
  • 介面和抽象類都不能被範例化,主要用於被其他類實現和繼承。
  • 介面和抽象類都可以包含抽象方法,實現介面或繼承抽象類的普通子類都必須實現這些抽象方法。

但介面和抽象類之間的差別非常大,這種差別主要體現在二者設計目的上。下面具體分析二者的差別。

介面作為系統與外界互動的視窗,介面體現的是一種規範。對於介面的實現者而言,介面規定了實現者必須向外提供哪些服務(以方法的形式來提供);對於介面的呼叫者而言,介面規定了呼叫者可以呼叫哪些服務,以及如何呼叫這些服務(就是如何來呼叫方法)。當在一個程式中使用介面時,介面是多個模組間的耦合標準;當在多個應用程式之間使用介面時,介面是多個程式之間的通訊標準。

從某種程度上來看,介面類似於整個系統的“總綱”,它制定了系統各模組應該遵循的標準,因此一個系統中的介面不應該經常改變。一旦介面被改變,對整個系統甚至其他系統的影響將是輻射式的,會導致系統中大部分類都需要改寫。

抽象類則不一樣,抽象類作為系統中多個子類的共同父類別,它所體現的是一種模板式設計。抽象類作為多個子類的抽象父類別,可以被當成系統實現過程中的中間產品,這個中間產品已經實現了系統的部分功能(那些已經提供實現的方法),但這個產品依然不能當成最終產品,必須有更進一步的完善,這種完善可能有幾種不同方式。

除此之外,介面和抽象類在用法上也存在差別,如下表所示:

引數 抽象類 介面
實現 子類使用 extends 關鍵字來繼承抽象類,如果子類不是抽象類,則需要提供抽象類中所有宣告的方法的實現。 子類使用 implements 關鍵字來實現介面,需要提供介面中所有宣告的方法的實現。
存取修飾符 可以用 public、protected 和 default 修飾 預設修飾符是 public,不能使用其它修飾符
方法 完全可以包含普通方法 只能包含抽象方法、靜態方法、預設方法和私有方法,不能為普通方法提供方法實現
變數 既可以定義普通成員變數,也可以定義靜態常數 只能定義靜態常數,不能定義普通成員變數
構造方法 抽象類裡的構造方法並不是用於建立物件,而是讓其子類呼叫這些構造方法來完成屬於抽象類的初始化操作 沒有構造方法
初始化塊 可以包含初始化塊 不能包含初始化塊
main 方法 可以有 main 方法,並且能執行 沒有 main 方法
與普通Java類的區別 抽象類不能範例化,除此之外和普通 Java 類沒有任何區別 是完全不同的型別
執行速度 比介面執行速度要快 需要時間去尋找在類種實現的方法,所以執行速度稍微有點慢

一個類最多只能有一個直接父類別,包括抽象類,但一個類可以直接實現多個介面,通過實現多個介面可以彌補 Java 單繼承的不足。

4)抽象類和介面的應用場景

抽象類的應用場景:
  1. 父類別只知道其子類應該包含怎樣的方法,不能準確知道這些子類如何實現這些方法的情況下,使用抽象類。
  2. 從多個具有相同特徵的類中抽象出一個抽象類,以這個抽象類作為子類的模板,從而避免了子類設計的隨意性。

介面的應用場景:
  1. 一般情況下,實現類和它的抽象類之前具有 "is-a" 的關係,但是如果我們想達到同樣的目的,但是又不存在這種關係時,使用介面。
  2. 由於 Java 中單繼承的特性,導致一個類只能繼承一個類,但是可以實現一個或多個介面,此時可以使用介面。

什麼時候使用抽象類和介面:
  • 如果擁有一些方法並且想讓它們有預設實現,則使用抽象類。
  • 如果想實現多重繼承,那麼必須使用介面。因為 Java 不支援多繼承,子類不能繼承多個類,但可以實現多個介面,因此可以使用介面。
  • 如果基本功能在不斷改變,那麼就需要使用抽象類。如果使用介面並不斷需要改變基本功能,那麼就需要改變所有實現了該介面的類。