接口
因?yàn)閖ava不支持多重繼承,所以有了接口鱼鸠,一個(gè)類只能繼承一個(gè)父類猛拴,但可以實(shí)現(xiàn)多個(gè)接口,接口本身也可以繼承多個(gè)接口瞧柔。
接口里面的成員變量默認(rèn)都是public static final類型的。必須被顯示的初始化睦裳。
3 . 接口里面的方法默認(rèn)都是public abstract類型的造锅。隱式聲明。
4 . 接口沒有構(gòu)造方法廉邑,不能被實(shí)例化哥蔚。
5 . 接口不能實(shí)現(xiàn)另一個(gè)接口,但可以繼承多個(gè)接口蛛蒙。
6 . 類如果實(shí)現(xiàn)了一個(gè)接口糙箍,那么必須實(shí)現(xiàn)接口里面的所有抽象方法,否則類要被定義為抽象類牵祟。
抽象類
如果將一個(gè)類聲明為abstract深夯,此類不能生成對(duì)象,只能被繼承使用诺苹。
抽象方法必須存在于抽象類中咕晋。
抽象類中可以有一般的變量和一般的方法。
子類繼承抽象類必須實(shí)現(xiàn)其中抽象方法收奔,除非子類為抽象類掌呜。
private void print(){};此語(yǔ)句表示方法的空實(shí)現(xiàn)坪哄。
abstract void print()质蕉; 此語(yǔ)句表示方法的抽象势篡,無實(shí)現(xiàn)。
接口和抽象類的區(qū)別
- 接口只能包含抽象方法模暗,抽象類可以包含普通方法禁悠。
- 接口只能定義靜態(tài)常量屬性,抽象類既可以定義普通屬性汰蓉,也可以定義靜態(tài)常量屬性绷蹲。
- 接口不包含構(gòu)造方法,抽象類里可以包含構(gòu)造方法顾孽。
抽象類不能被實(shí)例化祝钢,但不代表它不可以有構(gòu)造函數(shù),抽象類可以有構(gòu)造函數(shù)若厚,備繼承類擴(kuò)充
- 接口是核心拦英,其定義了要做的事情,包含了許多的方法测秸,但沒有定義這些方法應(yīng)該如何做疤估。
- 如果許多類實(shí)現(xiàn)了某個(gè)接口,那么每個(gè)都要用代碼實(shí)現(xiàn)那些方法
- 如果某一些類的實(shí)現(xiàn)有共通之處霎冯,則可以抽象出來一個(gè)抽象類铃拇,讓抽象類實(shí)現(xiàn)接口的公用的代碼,而那些個(gè)性化的方法則由各個(gè)子類去實(shí)現(xiàn)沈撞。
所以慷荔,抽象類是為了簡(jiǎn)化接口的實(shí)現(xiàn),他不僅提供了公共方法的實(shí)現(xiàn)缠俺,讓你可以快速開發(fā)显晶,又允許你的類完全可以自己實(shí)現(xiàn)所有的方法,不會(huì)出現(xiàn)緊耦合的問題壹士。
應(yīng)用場(chǎng)合很簡(jiǎn)單了
- 優(yōu)先定義接口
- 如果有多個(gè)接口實(shí)現(xiàn)有公用的部分磷雇,則使用抽象類,然后集成它躏救。
接口和抽象類的區(qū)別 --相信你看完不會(huì)再混淆了
我想唯笙,對(duì)于各位使用面向?qū)ο缶幊陶Z(yǔ)言的程序員來說,“接口”這個(gè)名詞一定不陌生盒使,但是不知各位有沒有這樣的疑惑:接口有什么用途睁本?它和抽象類有什么區(qū)別?能不能用抽象類代替接口呢忠怖?而且呢堰,作為程序員,一定經(jīng)常聽到“面向接口編程”這個(gè)短語(yǔ)凡泣,那么它是什么意思枉疼?有什么思想內(nèi)涵皮假?和面向?qū)ο缶幊淌鞘裁搓P(guān)系?本文將一一解答這些疑問骂维。
1.面向接口編程和面向?qū)ο缶幊淌鞘裁搓P(guān)系
首先惹资,面向接口編程和面向?qū)ο缶幊滩⒉皇瞧郊?jí)的,它并不是比面向?qū)ο缶幊谈冗M(jìn)的一種獨(dú)立的編程思想航闺,而是附屬于面向?qū)ο笏枷塍w系褪测,屬于其一部分×嗜校或者說侮措,它是面向?qū)ο缶幊腆w系中的思想精髓之一。
2.接口的本質(zhì)
接口乖杠,在表面上是由幾個(gè)沒有主體代碼的方法定義組成的集合體分扎,有唯一的名稱,可以被類或其他接口所實(shí)現(xiàn)(或者也可以說繼承)胧洒。它在形式上可能是如下的樣子:
interface InterfaceName
{
void Method1();
void Method2(int para1);
void Method3(string para2,string para3);
}
那么畏吓,接口的本質(zhì)是什么呢?或者說接口存在的意義是什么卫漫。我認(rèn)為可以從以下兩個(gè)視角考慮:
1)接口是一組規(guī)則的集合菲饼,它規(guī)定了實(shí)現(xiàn)本接口的類或接口必須擁有的一組規(guī)則。體現(xiàn)了自然界“如果你是……則必須能……”的理念列赎。
例如宏悦,在自然界中,人都能吃飯粥谬,即“如果你是人肛根,則必須能吃飯”辫塌。那么模擬到計(jì)算機(jī)程序中漏策,就應(yīng)該有一個(gè)IPerson(習(xí)慣上,接口名由“I”開頭)接口臼氨,并有一個(gè)方法叫Eat()掺喻,然后我們規(guī)定,每一個(gè)表示“人”的類储矩,必須實(shí)現(xiàn)IPerson接口感耙,這就模擬了自然界“如果你是人,則必須能吃飯”這條規(guī)則持隧。
從這里即硼,我想各位也能看到些許面向?qū)ο笏枷氲臇|西。面向?qū)ο笏枷氲暮诵闹宦挪Γ褪悄M真實(shí)世界只酥,把真實(shí)世界中的事物抽象成類褥实,整個(gè)程序靠各個(gè)類的實(shí)例互相通信、互相協(xié)作完成系統(tǒng)功能裂允,這非常符合真實(shí)世界的運(yùn)行狀況损离,也是面向?qū)ο笏枷氲木琛?/p>
2)接口是在一定粒度視圖上同類事物的抽象表示。注意這里我強(qiáng)調(diào)了在一定粒度視圖上绝编,因?yàn)椤巴愂挛铩边@個(gè)概念是相對(duì)的僻澎,它因?yàn)榱6纫晥D不同而不同。
例如十饥,在我的眼里窟勃,我是一個(gè)人,和一頭豬有本質(zhì)區(qū)別绷跑,我可以接受我和我同學(xué)是同類這個(gè)說法拳恋,但絕不能接受我和一頭豬是同類。但是砸捏,如果在一個(gè)動(dòng)物學(xué)家眼里谬运,我和豬應(yīng)該是同類,因?yàn)槲覀兌际莿?dòng)物垦藏,他可以認(rèn)為“人”和“豬”都實(shí)現(xiàn)了IAnimal這個(gè)接口梆暖,而他在研究動(dòng)物行為時(shí),不會(huì)把我和豬分開對(duì)待掂骏,而會(huì)從“動(dòng)物”這個(gè)較大的粒度上研究轰驳,但他會(huì)認(rèn)為我和一棵樹有本質(zhì)區(qū)別。
現(xiàn)在換了一個(gè)遺傳學(xué)家弟灼,情況又不同了级解,因?yàn)樯锒寄苓z傳,所以在他眼里田绑,我不僅和豬沒區(qū)別勤哗,和一只蚊子、一個(gè)細(xì)菌掩驱、一顆樹芒划、一個(gè)蘑菇乃至一個(gè)SARS病毒都沒什么區(qū)別,因?yàn)樗麜?huì)認(rèn)為我們都實(shí)現(xiàn)了IDescendable這個(gè)接口(注:descend vi. 遺傳)欧穴,即我們都是可遺傳的東西民逼,他不會(huì)分別研究我們,而會(huì)將所有生物作為同類進(jìn)行研究涮帘,在他眼里沒有人和病毒之分拼苍,只有可遺傳的物質(zhì)和不可遺傳的物質(zhì)。但至少调缨,我和一塊石頭還是有區(qū)別的疮鲫。
可不幸的事情發(fā)生了苟鸯,某日,地球上出現(xiàn)了一位偉大的人棚点,他叫列寧早处,他在熟讀MAX、恩格斯的辯證唯物主義思想巨著后瘫析,頗有心得砌梆,于是他下了一個(gè)著名的定義:所謂物質(zhì),就是能被意識(shí)所反映的客觀實(shí)在贬循。至此咸包,我和一塊石頭、一絲空氣杖虾、一條成語(yǔ)和傳輸手機(jī)信號(hào)的電磁場(chǎng)已經(jīng)沒什么區(qū)別了烂瘫,因?yàn)樵诹袑幍难劾铮覀兌际强梢员灰庾R(shí)所反映的客觀實(shí)在奇适。如果列寧是一名程序員坟比,他會(huì)這么說:所謂物質(zhì),就是所有同時(shí)實(shí)現(xiàn)了“IReflectabe”和“IEsse”兩個(gè)接口的類所生成的實(shí)例嚷往。(注:reflect v. 反映 esse n. 客觀實(shí)在)
也許你會(huì)覺得我上面的例子像在瞎掰葛账,但是,這正是接口得以存在的意義皮仁。面向?qū)ο笏枷牒秃诵闹唤凶龆鄳B(tài)性籍琳,什么叫多態(tài)性?說白了就是在某個(gè)粒度視圖層面上對(duì)同類事物不加區(qū)別的對(duì)待而統(tǒng)一處理贷祈。而之所以敢這樣做趋急,就是因?yàn)橛薪涌诘拇嬖凇O衲莻€(gè)遺傳學(xué)家势誊,他明白所有生物都實(shí)現(xiàn)了IDescendable接口呜达,那只要是生物,一定有Descend()這個(gè)方法键科,于是他就可以統(tǒng)一研究闻丑,而不至于分別研究每一種生物而最終累死漩怎。
可能這里還不能給你一個(gè)關(guān)于接口本質(zhì)和作用的直觀印象勋颖。那么在后文的例子和對(duì)幾個(gè)設(shè)計(jì)模式的解析中,你將會(huì)更直觀體驗(yàn)到接口的內(nèi)涵勋锤。
3.面向接口編程綜述
通過上文饭玲,我想大家對(duì)接口和接口的思想內(nèi)涵有了一個(gè)了解,那么什么是面向接口編程呢叁执?我個(gè)人的定義是:在系統(tǒng)分析和架構(gòu)中茄厘,分清層次和依賴關(guān)系矮冬,每個(gè)層次不是直接向其上層提供服務(wù)(即不是直接實(shí)例化在上層中),而是通過定義一組接口次哈,僅向上層暴露其接口功能胎署,上層對(duì)于下層僅僅是接口依賴,而不依賴具體類窑滞。
這樣做的好處是顯而易見的琼牧,首先對(duì)系統(tǒng)靈活性大有好處。當(dāng)下層需要改變時(shí)哀卫,只要接口及接口功能不變巨坊,則上層不用做任何修改。甚至可以在不改動(dòng)上層代碼時(shí)將下層整個(gè)替換掉此改,就像我們將一個(gè)WD的60G硬盤換成一個(gè)希捷的160G的硬盤趾撵,計(jì)算機(jī)其他地方不用做任何改動(dòng),而是把原硬盤拔下來共啃、新硬盤插上就行了占调,因?yàn)橛?jì)算機(jī)其他部分不依賴具體硬盤,而只依賴一個(gè)IDE接口移剪,只要硬盤實(shí)現(xiàn)了這個(gè)接口妈候,就可以替換上去。從這里看挂滓,程序中的接口和現(xiàn)實(shí)中的接口極為相似苦银,所以我一直認(rèn)為,接口(interface)這個(gè)詞用的真是神似赶站!
使用接口的另一個(gè)好處就是不同部件或?qū)哟蔚拈_發(fā)人員可以并行開工幔虏,就像造硬盤的不用等造CPU的,也不用等造顯示器的贝椿,只要接口一致想括,設(shè)計(jì)合理,完全可以并行進(jìn)行開發(fā)烙博,從而提高效率瑟蜈。
本篇文章先到這里。最后我想再啰嗦一句:面向?qū)ο蟮木枋悄M現(xiàn)實(shí)渣窜,這也可以說是我這篇文章的靈魂铺根。所以,多從現(xiàn)實(shí)中思考面向?qū)ο蟮臇|西乔宿,對(duì)提高系統(tǒng)分析設(shè)計(jì)能力大有脾益位迂。
對(duì)本文的補(bǔ)充:
仔細(xì)看了各位的回復(fù),非常高興能和大家一起討論技術(shù)問題。感謝給出肯定的朋友掂林,也要感謝提出意見和質(zhì)疑的朋友臣缀,這促使我更深入思考一些東西,希望能借此進(jìn)步泻帮。在這里我想補(bǔ)充一些東西精置,以討論一些回復(fù)中比較集中的問題。
1.關(guān)于“面向接口編程”中的“接口”與具體面向?qū)ο笳Z(yǔ)言中“接口”兩個(gè)詞
看到有朋友提出“面向接口編程”中的“接口”二字應(yīng)該比單純編程語(yǔ)言中的interface范圍更大锣杂。我經(jīng)過思考氯窍,覺得很有道理。這里我寫的確實(shí)不太合理蹲堂。我想狼讨,面向?qū)ο笳Z(yǔ)言中的“接口”是指具體的一種代碼結(jié)構(gòu),例如C#中用interface關(guān)鍵字定義的接口柒竞。而“面向接口編程”中的“接口”可以說是一種從軟件架構(gòu)的角度政供、從一個(gè)更抽象的層面上指那種用于隱藏具體底層類和實(shí)現(xiàn)多態(tài)性的結(jié)構(gòu)部件。從這個(gè)意義上說朽基,如果定義一個(gè)抽象類布隔,并且目的是為了實(shí)現(xiàn)多態(tài),那么我認(rèn)為把這個(gè)抽象類也稱為“接口”是合理的稼虎。但是用抽象類實(shí)現(xiàn)多態(tài)合理不合理衅檀?在下面第二條討論。
概括來說霎俩,我覺得兩個(gè)“接口”的概念既相互區(qū)別又相互聯(lián)系哀军。“面向接口編程”中的接口是一種思想層面的用于實(shí)現(xiàn)多態(tài)性打却、提高軟件靈活性和可維護(hù)性的架構(gòu)部件杉适,而具體語(yǔ)言中的“接口”是將這種思想中的部件具體實(shí)施到代碼里的手段。
2.關(guān)于抽象類與接口
看到回復(fù)中這是討論的比較激烈的一個(gè)問題柳击。很抱歉我考慮不周沒有在文章中討論這個(gè)問題猿推。我個(gè)人對(duì)這個(gè)問題的理解如下:
如果單從具體代碼來看,對(duì)這兩個(gè)概念很容易模糊捌肴,甚至覺得接口就是多余的蹬叭,因?yàn)閱螐木唧w功能來看,除多重繼承外(C#状知,Java中)秽五,抽象類似乎完全能取代接口。但是试幽,難道接口的存在是為了實(shí)現(xiàn)多重繼承筝蚕?當(dāng)然不是。我認(rèn)為铺坞,抽象類和接口的區(qū)別在于使用動(dòng)機(jī)起宽。使用抽象類是為了代碼的復(fù)用,而使用接口的動(dòng)機(jī)是為了實(shí)現(xiàn)多態(tài)性济榨。所以坯沪,如果你在為某個(gè)地方該使用接口還是抽象類而猶豫不決時(shí),那么可以想想你的動(dòng)機(jī)是什么擒滑。
看到有朋友對(duì)IPerson這個(gè)接口的質(zhì)疑腐晾,我個(gè)人的理解是,IPerson這個(gè)接口該不該定義丐一,關(guān)鍵看具體應(yīng)用中是怎么個(gè)情況藻糖。如果我們的項(xiàng)目中有Women和Man,都繼承Person库车,而且Women和Man絕大多數(shù)方法都相同巨柒,只有一個(gè)方法DoSomethingInWC()不同(例子比較粗俗,各位見諒)柠衍,那么當(dāng)然定義一個(gè)AbstractPerson抽象類比較合理洋满,因?yàn)樗梢园哑渌蟹椒ǘ及M(jìn)去,子類只定義DoSomethingInWC()珍坊,大大減少了重復(fù)代碼量牺勾。
但是,如果我們程序中的Women和Man兩個(gè)類基本沒有共同代碼阵漏,而且有一個(gè)PersonHandle類需要實(shí)例化他們驻民,并且不希望知道他們是男是女,而只需把他們當(dāng)作人看待履怯,并實(shí)現(xiàn)多態(tài)川无,那么定義成接口就有必要了。
總而言之虑乖,接口與抽象類的區(qū)別主要在于使用的動(dòng)機(jī)懦趋,而不在于其本身。而一個(gè)東西該定義成抽象類還是接口疹味,要根據(jù)具體環(huán)境的上下文決定仅叫。
再者,我認(rèn)為接口和抽象類的另一個(gè)區(qū)別在于糙捺,抽象類和它的子類之間應(yīng)該是一般和特殊的關(guān)系诫咱,而接口僅僅是它的子類應(yīng)該實(shí)現(xiàn)的一組規(guī)則。(當(dāng)然洪灯,有時(shí)也可能存在一般與特殊的關(guān)系坎缭,但我們使用接口的目的不在這里)如,交通工具定義成抽象類,汽車掏呼、飛機(jī)坏快、輪船定義成子類,是可以接受的憎夷,因?yàn)槠嚸Ш琛w機(jī)、輪船都是一種特殊的交通工具拾给。再譬如Icomparable接口祥得,它只是說,實(shí)現(xiàn)這個(gè)接口的類必須要可以進(jìn)行比較蒋得,這是一條規(guī)則级及。如果Car這個(gè)類實(shí)現(xiàn)了Icomparable,只是說额衙,我們的Car中有一個(gè)方法可以對(duì)兩個(gè)Car的實(shí)例進(jìn)行比較创千,可能是比哪輛車更貴,也可能比哪輛車更大入偷,這都無所謂追驴,但我們不能說“汽車是一種特殊的可以比較”,這在文法上都不通疏之。