接口為什么不能有構造函數


以舉例的方式說到如何區分抽象類和接口,這里我們從Java語法談起,使我們更加了解這兩者的內在區別。它們的語法區別:1)接口不能有構造方法,抽象類可以有。2)接口不能有方法體,抽象類可以有。3)接口不能有靜態方法,抽象類可以有。4)在接口中凡是變量必須是public static final,而在抽象類中沒有要求。
忽然有此一文,是因為同學疑惑道:抽象類居然還有構造方法,又不能直接用來new。我的解釋是平時在抽象類中對於構造方法的存在,沒有什么印象,是因為IDE默認為你生成了一個無參構造方法,也可以顯式地寫出構造方法,這個構造方法,是用來被子類調用的,因為任何子類都必須調用從Object開始的所有父親的構造方法,才算完成初始化工作。那么我引申一下,問他們,接口有構造方法嗎?他們的理解,抽象可以有,為什么接口不可以有?!那么在接口里寫入構造方法時,編譯器提示:Interfaces cannot have constructors。這又何解?
從語法的角度來說,抽象類必須有構造方法,而接口嚴禁有構造方法,這本身也說明了它們性質的不同。抽象類是一個類,別的類是用關鍵字 extends 來繼承下來,並擴展的,有非常強的is-a的關系,這種關系一般來說符合里氏代換原則。而接口,是被其他類用關鍵字 implements 來實現接口定義的方法的。如果沒什么區別,何必整出兩個不同的關鍵字。 接口只是定義功能和行為規范,如果一個類實現了一個接口,那么這個類必須遵守這個接口的方法約定,但沒有is-a的關系。把牆壁上的“小學生行為規范”想象成一個接口,那么是小學生必須遵守這個約定,但小學生不是“行為規范”。
構造方法是用來在對象初始化前對對象進行一些預處理的,提供了實例化一個具體東西的入口。接口只是聲明而已,不一定要進行什么初始化,就算要進行初始化,也可以到實現接口的那一些類里面去初始化。接口只是用來表述動作,表述規范來的,可以new一台computer,但我們無法new一個IDE、SATA、PCI、PS-2。因此,接口要構造方法何用?接口是一種規范,被調用時,主要關注的是里邊的方法,而方法是不需要初始化的,類可以實現多個接口,若多個接口都有自己的構造器,則不好決定構造器的調用次序,構造器是屬於類自己的,不能繼承,因為是純虛的,接口不需要構造方法。而抽象類是具體類的祖先,即使是石器時代,也總要干些初始化的工作,抽象類雖然是不能直接實例化,但實例化子類的時候,就會初始化父類,不管父類是不是抽象類都,都會調用父類的構造方法,初始化一個類,先初始化父類,有沒有說初始化接口。
再拿汽車的例子來說明兩者的區別,Car, Track, Van 是 Vehicle 抽象類的子類,那么你可以說小嬌車是車子,拖拉機是車子,貨車是車子。而做為他們共同的父類,會做一些初始化工作,如加汽油、機油、冷卻液。另外所有車子具有共同屬性,輪子,方向盤,油門等。Brake 是一個剎車動作接口,這個規范要求車子實現了它,必須有能力把速度減到零,只是實現途徑不一樣,或者是鼓剎,或者是碟剎。或者是效果不一樣,有的剎車靈一點,有的剎車差一點。
在抽象類和接口均可以被考慮的地方,接口首先是被提倡使用的,在語法上沒有is-a的關系,使用起來更加靈活,另外可以多實現畢竟是一種難得的資源。而抽象類當存在大家共同的實現方法,或者有很多屬性操作時,才是首選,當考慮使用抽象類時,在可預見的未來,它要體現出被繼承時非常強烈的is-a關系。
接口不能有方法體,就是強制接口定義者不能給接口增加一些詳細的實現,指定的必須是純虛的接口,對於架構者來說,它需要做的就是定義一個可以理解的接口名,參數列表,以及返回類型。而抽象類是可以有自己的實現方法,這個方法可以被用來被執行。有時候,我們會誤以為抽象類中的方法不能用super顯示調用,因為super是指代父類對象,而抽象類MS不能有對象。但事實上可以,任何子類實際的對象,都可以理解成父類的對象。
接口的所有方法都是抽象的,而抽象方法是沒有static,有static的方法是不能override的,不能實現多態,所以這樣定義接口才有意義,接口中定義的方法目的很明確:就是給實現類去實現,如果你在接口中將方法聲明為靜態的(與具體的實例無關),但接口中的方法又要求必須被實現類去實現(可能會有多個實現類),這豈不是自相矛盾!如果硬要加上static上去,編譯器會友好提示:Illegal modifier for the interface method FF.f(); only public & abstract are permitted。說到底,不能再加任何除public 和 abstract 的任何修飾符了,如:private, protected, final, static.
數據成員沒有多態的概念,只有可不可以被訪問的說法,如果是公有的數據成員是在任何地方都可以被訪問和修改的,那么接口定義的數據成員如果是私有的,又何必定義,因為它沒有方法,就是說沒有任何方法對這個數據成員可以操作。如果是公有的,誰都可以修改,那么,多重實現多個接口,這個數據不是改得亂了套?所以接口一般不允許有數據成員,但如果真的有,明確默認即為public final static, 嚴格保證對於所有實現者來說只有一份原始的數據。
那么在架構設計時,如何使用抽象類和接口來解決問題,是一個非常復雜的問題,抽象類更側重於歸納同一父類的子類的共同特征,如果屬性,方法;接口更側重於定義任意的類有沒有相同語義的方法,它是一個一經定義不輕易更改的規范,它的修改在項目中,往往是動一發而牽全身,即使有考慮不周到的地方,也會使用新增接口的形式去彌補。其實abstract class表示的是"is-a"關系,interface表示的是"like-a"關系。最頂級的是接口,然后是抽象類實現接口,最后才到具體類實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM