抽象類和接口的相同點與不同點

在面向對象的程序設計(英語:Object-oriented programming,縮寫:OOP)中,對象是一個由信息及對信息進行處理的描述所組成的整體,是對現實世界的抽象。

在計算機的世界裏,用類來表示現實世界的事情。對象的三個特性:對象的行爲(能在對象上施加哪些操作);對象的形態(當施加那些操作,對象做什麼迴應);對象的表示(在相同的行爲和形態下有什麼不同);

面向對象內容:

           類:定義了相同事物的抽象點,包括了數據的形式和數據的操作(即類的屬性和方法);對象是類的實例;

           類的屬性和方法都可以public 、private、protected 三個修飾符。

          屬性還可以有常量,用關鍵字 const 來定義;

          借用別人的智慧:php面向對象中static靜態屬性和靜態方法。關於他們的調用,需要弄明白了他們在內存中存放位置,這樣就容易理解了。總結如下:

  •   靜態屬性不需要實例化就可以調用;因爲靜態屬性存放在類裏,調用方法爲"類名::屬性名";
  •   靜態方法不需要實例化就可以調用;同上;(通過對象—>靜態方法也可以調用)。
  •   靜態方法發不能調用非靜態屬性。因爲非靜態屬性需要實例化後,存放到對象裏;
  •   靜態方法可以調用非靜態方法,使用self關鍵詞。PHP裏,一個方法被self::後,它就自動轉變爲靜態方法;      

                                                                                                                                                                                                     PHP類的繼承是單繼承,多層次。   

面向對象的編程,有一個特徵,就是抽象:接口、抽象類、類;接口抽象的是抽象類的方法,與實現接口子類的關係是"有沒有"的關係,即子類抽象的事物,有沒有這個方法。抽象類抽象的是的方法,與實現抽象類的子類的關係是"是不是"的關係。

          總結類是對事物的抽象,抽象類是對類的抽象,接口是對抽象類的抽象。

          舉例:抽象類是對一種事物的抽象,即對類抽象,而接口是對行爲的抽象。抽象類是對整個類整體進行抽象,包括屬性、行爲,但是接口卻是對類局部(行爲)進行抽象。飛機和鳥是不同類的事物,但是它們都有一個共性,就是都會飛。那麼在設計的時候,可以將飛機設計爲一個類Airplane,將鳥設計爲一個類Bird,但是不能將 飛行 這個特性也設計爲類,因此它只是一個行爲特性,並不是對一類事物的抽象描述。此時可以將 飛行 設計爲一個接口Fly,包含方法fly( ),然後Airplane和Bird分別根據自己的需要實現Fly這個接口。然後至於有不同種類的飛機,比如戰鬥機、民用飛機等直接繼承Airplane即可,對於鳥也是類似的,不同種類的鳥直接繼承Bird類即可。從這裏可以看出,繼承是一個 "是不是"的關係,而 接口 實現則是 "有沒有"的關係。如果一個類繼承了某個抽象類,則子類必定是抽象類的種類,而接口實現則是有沒有、具備不具備的關係,比如鳥是否能飛(或者是否具備飛行這個特點),能飛行則可以實現這個接口,不能飛行就不實現這個接口。

         下面要注意一個問題:在《JAVA編程思想》一書中,將抽象類定義爲“包含抽象方法的類”,但是後面發現如果一個類不包含抽象方法,只是用abstract修飾的話也是抽象類。也就是說抽象類不一定必須含有抽象方法。個人覺得這個屬於鑽牛角尖的問題吧,因爲如果一個抽象類不包含任何抽象方法,爲何還要設計爲抽象類?所以暫且記住這個概念吧,不必去深究爲什麼。


  

抽象類是什麼

抽象類不能創建實例,它只能作爲父類被繼承抽象類是從多個具體類中抽象出來的父類,它具有更高層次的抽象。從多個具有相同特徵的類中抽象出一個抽象類,以這個抽象類作爲其子類的模板,從而避免了子類的隨意性。

(1) 抽象方法只作聲明,而不包含實現,可以看成是沒有實現體的虛方法

(2) 抽象類不能被實例化

(3) 抽象類可以但不是必須有抽象屬性和抽象方法,但是一旦有了抽象方法,就一定要把這個類聲明爲抽象類

(4) 具體派生類必須覆蓋基類的抽象方法

(5) 抽象派生類可以覆蓋基類的抽象方法,也可以不覆蓋。如果不覆蓋,則其具體派生類必須覆蓋它們


接口是什麼

(1) 接口不能被實例化

(2) 接口只能包含方法聲明

(3) 接口的成員包括方法、屬性、索引器、事件

(4) 接口中不能包含常量、字段(域)、構造函數、析構函數、靜態成員


接口和抽象類的區別

(1)抽象類可以有構造方法,接口中不能有構造方法。

(2)抽象類中可以有普通成員變量,接口中沒有普通成員變量(接口中的方法定義默認爲public abstract類型,接口中的成員變量類型默認爲public static final)

(3)抽象類中可以包含靜態方法,接口中不能包含靜態方法

(4) 一個類可以實現多個接口,但只能繼承一個抽象類。

(5)接口可以被多重實現,抽象類只能被單一繼承

(6)如果抽象類實現接口,則可以把接口中方法映射到抽象類中作爲抽象方法而不必實現,而在抽象類的子類中實現接口中方法

  (7)  接口定義的關鍵字interface;抽象類定義的關鍵字abstract

 (8)抽象類繼承的關鍵字extends,接口的實現關鍵字implements

   (9)  抽象類可以提供成員方法的實現細節,可以用public 、protected、default這些修飾符;接口只能是public abstract方法

 

  (10) 抽象類的速度比接口能快一點,因爲接口需要時間去尋找在類中實現的方法

   (11)添加新方法:如果你往抽象類中添加新的方法,你可以給它提供默認的實現,因此你不需要改變你現在的代碼;如果你往接口中添加方法,那麼你必須改變實現該接口的類。

 

    (12)繼承一個抽象類的時候,子類必須定義父類中的所有抽象方法;另外,這些方法的訪問控制必須和父類中一樣(或者更爲寬鬆)。例如某個抽象方法被聲明爲受保護的,那麼子類中實現的方法就應該聲明爲受保護的或者公有的,而不能定義爲私有的。此外方法的調用方式必須匹配,即類型和所需參數數量必須一致。例如,子類定義了一個可選參數,而父類抽象方法的聲明裏沒有,則兩者的聲明並無衝突。

     

設計層面不同,抽象類作爲很多子類的父類,它是一種模板式設計。而接口是一種行爲規範,它是一種輻射式設計。什麼是模板式設計?最簡單例子,大家都用過ppt裏面的模板,如果用模板A設計了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,如果它們的公共部分需要改動,則只需要改動模板A就可以了,不需要重新對ppt B和ppt C進行改動。而輻射式設計,比如某個電梯都裝了某種報警器,一旦要更新報警器,就必須全部更新。也就是說對於抽象類,如果需要添加新的方法,可以直接在抽象類中添加具體的實現,子類可以不進行變更;而對於接口則不行,如果接口進行了變更,則所有實現這個接口的類都必須進行相應的改動。

  下面看一個網上流傳最廣泛的例子:門和警報的例子:門都有open( )和close( )兩個動作,此時我們可以定義通過抽象類和接口來定義這個抽象概念:

1

2

3

4

abstract class Door {

    public abstract void open();

    public abstract void close();

}

  或者:

1

2

3

4

interface Door {

    public abstract void open();

    public abstract void close();

}

  但是現在如果我們需要門具有報警alarm( )的功能,那麼該如何實現?下面提供兩種思路:

  1)將這三個功能都放在抽象類裏面,但是這樣一來所有繼承於這個抽象類的子類都具備了報警功能,但是有的門並不一定具備報警功能;

  2)將這三個功能都放在接口裏面,需要用到報警功能的類就需要實現這個接口中的open( )和close( ),也許這個類根本就不具備open( )和close( )這兩個功能,比如火災報警器。

  從這裏可以看出, Door的open() 、close()和alarm()根本就屬於兩個不同範疇內的行爲,open()和close()屬於門本身固有的行爲特性,而alarm()屬於延伸的附加行爲。因此最好的解決辦法是單獨將報警設計爲一個接口,包含alarm()行爲,Door設計爲單獨的一個抽象類,包含open和close兩種行爲。再設計一個報警門繼承Door類和實現Alarm接口。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

interface Alram {

    void alarm();

}

 

abstract class Door {

    void open();

    void close();

}

 

class AlarmDoor extends Door implements Alarm {

    void oepn() {

      //....

    }

    void close() {

      //....

    }

    void alarm() {

      //....

    }

}


接口和抽象類的相同點

 

(1) 都不能被實例化

(2) 都可以包含方法聲明

(3) 派生類必須實現未實現的方法


  抽象類和接口的使用時機

   

在設計類的時候,首先考慮用接口抽象出類的特性,當你發現某些方法可以複用的時候,可以使用抽象類來複用代碼。簡單說,接口用於抽象事物的特性,抽象類用於代碼複用

當然,不是所有類的設計都要從接口到抽象類,再到類。程序設計本就沒有絕對的範式可以遵循。根據自己的需求設計。

 

      

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章