Java中的接口與抽象類

抽象類和接口都是用來體現OOP中的抽象概念,都可以用來實現多態。

1. 抽象類

抽象類表達的是“is-a”的關係,是對多個具體類公共部分的抽象,定義了子類是什麼(如Bird、Duck本質上都是Animal,即可以將其抽象爲Animal類),由於抽象類沒有足夠的信息,是不完整的,所以必須由具體的子類來繼承它並實現抽象方法。

抽象類定義

如果一個類含有抽象方法(abstact修飾的方法),則其爲抽象類,在class關鍵字前使用abstract進行修飾。抽象類是爲了繼承而存在的,即抽象類不能直接創建實例,必須通過子類繼承並實現其抽象方法。抽象類中並不只有抽象方法,還可以有提供實現的具體方法和成員變量。

抽象類特點

  1. 抽象類不能被實例化,必須通過子類繼承;
  2. 抽象方法必須爲public或protected(如果爲private,就不能被子類繼承了),默認爲public;
  3. abstract不能與final同時修飾抽象類中的class和方法,因爲這樣就不能被繼承和重寫了。
  4. 如果一個類繼承抽象類,則子類必須實現父類的抽象方法,如果子類沒有實現父類的抽象方法,則必須將子類也定義爲抽象類。

2. 接口

接口表達的是“has-a”的關係,是對行爲的抽象,並不能表達子類的本質特徵(即子類是什麼),子類實現了接口表面其具有該接口提供的行爲,(如有一個Flyable接口,提供fly()方法,Bird實現該接口時,必須實現fly()方法,表明其具有飛行行爲)。因爲Java不允許多繼承,通過實現接口可以間接實現多繼承。

  1. 接口的所有方法都不能有具體的實現,即所有方法都是抽象方法(JDK8可以有默認方法實現),可以有成員變量,但會被隱式的指定爲public static final,而方法會被隱式地指定爲public abstract方法且只能是public abstract方法;
  2. 實現接口的非抽象類必須要實現該接口的所有方法。抽象類可以不用實現。

3. 抽象類和接口區別

抽象類和接口都用來表達面向對象中的抽象概念,都可以作爲超類型提供多態的實現。抽象類作爲父類對子類中公共的特徵進行抽象(所以必須是對具有一組相同概念本質的子類,如都是動物),而接口不用管子類具體是什麼,只需要提供行爲,對行爲進行抽象,如Flyable接口提供飛行行爲,Bird和AirPlane都可以實現該接口,並實現其中的飛行方法,但這兩個類本質是不同的類。所以Java提供抽象類和接口,一個用來抽象子類是什麼(is-a),一個用來抽象子類可以具有哪些行爲方法(has-a)。二者可以結合起來使用,實現多個接口。

語法層面

  1. 抽象類可以擁有任意範圍的成員數據,同時也可以擁有自己的非抽象方法,但是接口方式中,它僅能夠有靜態、不能修改的成員數據(但是我們一般是不會在接口中使用成員數據),同時它所有的方法都必須是抽象的。在某種程度上來說,接口是抽象類的特殊化。
  2. 一個類只能繼承一個抽象類,可以實現多個接口,從某種程度上說,接口允許Java的多繼承。
  3. 接口中不能有靜態代碼塊和靜態方法,而抽象類可以有。

設計層面

  1. 抽象層次不同:抽象類是對類的本質特徵進行抽象,接口是對行爲進行抽象。抽象類是對整個類整體進行抽象,包括屬性、行爲,但是接口卻是對類局部(行爲)進行抽象。
  2. 跨域不同:抽象類所跨域的是具有相似特點的類,而接口則可以跨不同的類。繼承抽象類的子類必須和其父類在概念本質上是相同的,而實現接口的子類可以不存在任何關係,僅僅是實現了接口定義的契約而已。
  3. 設計層次不同:抽象類是自底向上抽象而來的,接口是自頂向下設計出來的。

舉個例子:

門和警報的例子:有一個Door類,具有open()和close()兩個行爲。我們可以通過抽象類和接口來定義這個概念:

抽象類:

abstract class Door{
    abstract void open();
    abstract void close();
}

接口:

interface Door {
    void open();
    void close();
}

現在要給門加一個報警的功能alarm(),如何實現呢,有兩種思路:

  1. 將報警方法放在抽象類裏,但是這樣一來所有繼承於這個抽象類的子類都具備了報警功能,但是並不是所有的門並一定具備報警功能;
  2. 將這三個功能都放在接口裏面,需要用到報警功能的類就需要實現這個接口中的open( )和close( ),也許這個類根本就不具備open( )和close( )這兩個功能,比如火災報警器。

從這裏可以看出,open()和close()是所有Door的固有方法,所以可以將其抽象出來並在抽象類中定義,而alarm()方法屬於附加行爲,所以應該將其單獨抽象爲一個接口,代表具有報警行爲,這樣不只門可以實現該接口,其他具有報警功能的都可以實現。

所以open()和close()放在抽象類裏,alarm()單獨用一個接口來表示:

interface Alram {
    void alarm();
}
 
abstract class Door {
    void open();
    void close();
}
 
class AlarmDoor extends Door implements Alarm {
    void oepn() {
      //....
    }
    void close() {
      //....
    }
    void alarm() {
      //....
    }
}

參考:

  1. https://blog.csdn.net/chenssy/article/details/12858267
  2. https://www.cnblogs.com/dolphin0520/p/3811437.html
  3. https://juejin.im/entry/59fa7b07518825076a0c4a0c
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章