比較區别
與具體類比較
抽象類不能直接實例化,并且對抽象類使用new運算符會導緻編譯時錯誤。雖然一些變量和值在編譯時的類型可以是抽象的,但是這樣的變量和值必須或者為null,或者含有對非抽象類的實例的引用(此非抽象類是從抽象類派生的)。
允許(但不要求)抽象類包含抽象成員。
抽象類不能被密封。
與接口比較
抽象類表示該類中可能已經有一些方法的具體定義,但是接口就僅僅隻能定義各個方法的界面(方法名,參數列表,返回類型),并不關心具體細節。
接口是引用類型的,和抽象類的相似之處有三點:
不能實例化;
包含未實現的方法聲明;
派生類必須實現未實現的方法,抽象類是抽象方法,接口則是所有成員(不僅是方法包括其他成員)。
抽象類與接口緊密相關。然而接口又比抽象類更抽象,這主要體現在它們的差别上:
類可以實現無限個接口,但僅能從一個抽象(或任何其他類型)類繼承,從抽象類派生的類仍可實現接口,從而得出接口是用來解決多重繼承問題的。
抽象類當中可以存在非抽象的方法,可接口不能,且它裡面的方法隻是一個聲明必須用public來修飾沒有具體實現的方法。
抽象類中的成員變量可以被不同的修飾符來修飾,可接口中的成員變量默認的都是靜态常量(static final)。
抽象類是對象的抽象,然而接口是一種行為規範。
抽象類裡面可以有非抽象方法但接口裡隻能有抽象方法聲明方法的存在而不去實現它的類被叫做抽像類(abstract class),它用于要創建一個體現某些基本行為的類,并為該類聲明方法,但不能在該類中實現該類的情況。不能創建abstract類的實例。然而可以創建一個變量,其類型是一個抽像類,并讓它指向具體子類的一個實例。不能有抽像構造函數或抽像靜态方法。Abstract類的子類為它們父類中的所有抽像方法提供實現,否則它們也是抽像類為。取而代之,在子類中實現該方法。知道其行為的其它類可以在類中實現這些方法。接口(interface)是抽像類的變體。在接口中,所有方法都是抽像的。
多繼承性可通過實現這樣的接口而獲得。接口中的所有方法都是抽像的,沒有一個有程序體。接口隻可以定義static final成員變量。接口的實現與子類相似,除了該實現類不能從接口定義中繼承行為。當類實現特殊接口時,它定義(即将程序體給予)所有這種接口的方法。然後,它可以在實現了該接口的類的任何對像上調用接口的方法。由于有抽像類,它允許使用接口名作為引用變量的類型。通常的動态聯編将生效。引用可以轉換到接口類型或從接口類型轉換,instanceof運算符可以用來決定某對象的類是否實現了接口
運用要求
C++
标準c++沒有abstract關鍵字,代之使用純虛類實現類似的功能,詳見詞條“虛類”。
在實現接口時,常寫一個抽象類,來實現接口中的某些子類所需的通用方法,接着在編寫各個子類時,即可繼承該抽象類來使用,省去在每個都要實現通用的方法的困擾。
C#
抽象類應主要用于關系密切的對象,而接口最适合為不相關的類提供通用功能。
接口着重于CAN-DO關系類型,而抽象類則偏重于IS-A式的關系。
接口多定義對象的行為;抽象類多定義對象的屬性。
如果預計會出現版本問題,可以創建“抽象類”。例如,創建了狗(Dog)、雞(Chicken)和鴨(Duck),那麼應該考慮抽象出動物(Animal)來應對以後可能出現豬馬牛的事情。而向接口中添加新成員則會強制要求修改所有派生類,并重新編譯,所以版本式的問題最好以抽象類來實現。
從抽象類派生的非抽象類必須包括繼承的所有抽象方法和抽象訪問器的實現。
對抽象類不能使用new關鍵字,也不能被密封,原因是抽象類不能被實例化。
在抽象方法聲明中不能使用static或virtual修飾符。
Java
abstract class在Java語言中表示的是一種繼承關系,一個類隻能使用一次繼承關系。但是,一個類卻可以實現多個interface。
在abstract class中可以有自己的數據成員,也可以有非abstarct的成員方法,而在interface中,隻能夠有靜态的不能被修改的數據成員(也就是必須是static final的,不過在interface中一般不定義數據成員),所有的成員方法都是abstract的。
abstract class和interface所反映出的設計理念不同。其實abstract class表示的是"is-a"關系,interface表示的是"like-a"關系。
實現抽象類和接口的類必須實現其中的所有方法。抽象類中可以有非抽象方法。接口中則不能有實現方法。
接口中定義的變量默認是public static final型,且必須給其初值,所以實現類中不能重新定義,也不能改變其值。
抽象類中的變量默認是 friendly型,其值可以在子類中重新定義,也可以重新賦值。
接口中的方法默認都是 public,abstract類型的。
運用實例
C++
為了讓一個類成為抽象類,至少必須有一個純虛函數。包含至少一個純虛函數的類視為抽象類。
純虛函數形式如下:
例如,類A有兩個純虛函數lock()、unlock()和一個虛析構函數:
将函數lock()和unlock()初始化為0使它們成為純虛函數,沒有0這個初使化器,它們僅僅是虛函數。
抽象類對于提供模式、藍圖和後代類遵循的原則有用,如果遵循了藍圖的語義,後代類的行為可能按抽象類提供者和使用者所期望的那樣。
通過使用抽象類,C++程序員可以提供C++組件的規範,在它的構建中指導組件的實現者。
C#
抽象類提供多個派生類共享基類的公共定義,它既可以提供抽象方法,也可以提供非抽象方法。如果派生類沒有實現所有的抽象方法,則該派生類也必須聲明為抽象類。另外,實現抽象方法由overriding方法來實現。
定義方法為:
Java
假設在問題領域中有一個關于Door的抽象概念,該Door具有執行兩個動作open和close,此時可以通過abstract class或者interface來定義一個表示該抽象概念的類型,定義方式分别如下所示:
使用abstract class方式定義Door:
使用interface方式定義Door:
其他具體的Door類型可以extends使用abstract class方式定義的Door或者implements使用interface方式定義的Door。就此看來,使用abstract class和interface沒有大的區别。
但如果需求要求Door還要具有報警的功能,就能得出差别。既然open、close和alarm屬于兩個不同的概念,根據ISP原則應該把它們分别定義在代表這兩個概念的抽象類中。
對于問題領域的理解是:AlarmDoor在概念本質上是Door,同時它有具有報警的功能。說明它又能夠完成報警概念中定義的行為,所以報警概念可以通過interface方式定義。如下所示:
這種實現方式基本上能夠明确的反映出對于問題領域的理解,正确的揭示設計意圖。
運用意義
在面向對象方法中,抽象類主要用來進行類型隐藏。構造出一個固定的一組行為的抽象描述,但是這組行為卻能夠有任意個可能的具體實現方式。這個抽象描述就是抽象類,而這一組任意個可能的具體實現則表現為所有可能的派生類。模塊可以操作一個抽象體。由于模塊依賴于一個固定的抽象體,因此它可以是不允許修改的;同時,通過從這個抽象體派生,也可擴展此模塊的行為功能。為了能夠實現面向對象設計的一個最核心的原則OCP(Open-Closed Principle),抽象類是其中的關鍵所在。