對於面向對象編程來講,抽象是它的一大特徵之一。在Java中,能夠經過兩種形式來體現OOP的抽象:接口和抽象類。這二者有太多類似的地方,又有太多不一樣的地方。不少人在初學的時候會覺得它們能夠隨意互換使用,可是實際則否則。今天咱們就一塊兒來學習一下Java中的接口和抽象類。下面是本文的目錄大綱:java
一.抽象類編程
二.接口函數
三.抽象類和接口的區別學習
如有不正之處,請多多諒解並歡迎批評指正,不甚感激。spa
在瞭解抽象類以前,先來了解一下抽象方法。抽象方法是一種特殊的方法:它只有聲明,而沒有具體的實現。抽象方法的聲明格式爲:設計
abstract void fun();
抽象方法必須用abstract關鍵字進行修飾。若是一個類含有抽象方法,則稱這個類爲抽象類,抽象類必須在類前用abstract關鍵字修飾。由於抽象類中含有無具體實現的方法,因此不能用抽象類建立對象。code
下面要注意一個問題:在《JAVA編程思想》一書中,將抽象類定義爲「包含抽象方法的類」,可是後面發現若是一個類不包含抽象方法,只是用abstract修飾的話也是抽象類。也就是說抽象類不必定必須含有抽象方法。我的以爲這個屬於鑽牛角尖的問題吧,由於若是一個抽象類不包含任何抽象方法,爲什麼還要設計爲抽象類?因此暫且記住這個概念吧,沒必要去深究爲何。對象
[public] abstract class ClassName { abstract void fun(); }
從這裏能夠看出,抽象類就是爲了繼承而存在的,若是你定義了一個抽象類,卻不去繼承它,那麼等於白白建立了這個抽象類,由於你不能用它來作任何事情。對於一個父類,若是它的某個方法在父類中實現出來沒有任何意義,必須根據子類的實際需求來進行不一樣的實現,那麼就能夠將這個方法聲明爲abstract方法,此時這個類也就成爲abstract類了。繼承
包含抽象方法的類稱爲抽象類,但並不意味着抽象類中只能有抽象方法,它和普通類同樣,一樣能夠擁有成員變量和普通的成員方法。注意,抽象類和普通類的主要有三點區別:接口
1)抽象方法必須爲public或者protected(由於若是爲private,則不能被子類繼承,子類便沒法實現該方法),缺省狀況下默認爲public。
2)抽象類不能用來建立對象;
3)若是一個類繼承於一個抽象類,則子類必須實現父類的抽象方法。若是子類沒有實現父類的抽象方法,則必須將子類也定義爲爲abstract類。
在其餘方面,抽象類和普通的類並無區別。
接口,英文稱做interface,在軟件工程中,接口泛指供別人調用的方法或者函數。從這裏,咱們能夠體會到Java語言設計者的初衷,它是對行爲的抽象。在Java中,定一個接口的形式以下:
[public] interface InterfaceName { }
接口中能夠含有 變量和方法。可是要注意,接口中的變量會被隱式地指定爲public static final變量(而且只能是public static final變量,用private修飾會報編譯錯誤),而方法會被隱式地指定爲public abstract方法且只能是public abstract方法(用其餘關鍵字,好比private、protected、static、 final等修飾會報編譯錯誤),而且接口中全部的方法不能有具體的實現,也就是說,接口中的方法必須都是抽象方法。從這裏能夠隱約看出接口和抽象類的區別,接口是一種極度抽象的類型,它比抽象類更加「抽象」,而且通常狀況下不在接口中定義變量。
要讓一個類遵循某組特意的接口須要使用implements關鍵字,具體格式以下:
class ClassName implements Interface1,Interface2,[....]{ }
能夠看出,容許一個類遵循多個特定的接口。若是一個非抽象類遵循了某個接口,就必須實現該接口中的全部方法。對於遵循某個接口的抽象類,能夠不實現該接口中的抽象方法。
1.語法層面上的區別
1)抽象類能夠提供成員方法的實現細節,而接口中只能存在public abstract 方法;
2)抽象類中的成員變量能夠是各類類型的,而接口中的成員變量只能是public static final類型的;
3)接口中不能含有靜態代碼塊以及靜態方法,而抽象類能夠有靜態代碼塊和靜態方法;
4)一個類只能繼承一個抽象類,而一個類卻能夠實現多個接口。
2.設計層面上的區別
1)抽象類是對一種事物的抽象,即對類抽象,而接口是對行爲的抽象。抽象類是對整個類總體進行抽象,包括屬性、行爲,可是接口倒是對類局部(行爲)進行抽象。舉個簡單的例子,飛機和鳥是不一樣類的事物,可是它們都有一個共性,就是都會飛。那麼在設計的時候,能夠將飛機設計爲一個類Airplane,將鳥設計爲一個類Bird,可是不能將 飛行 這個特性也設計爲類,所以它只是一個行爲特性,並非對一類事物的抽象描述。此時能夠將 飛行 設計爲一個接口Fly,包含方法fly( ),而後Airplane和Bird分別根據本身的須要實現Fly這個接口。而後至於有不一樣種類的飛機,好比戰鬥機、民用飛機等直接繼承Airplane便可,對於鳥也是相似的,不一樣種類的鳥直接繼承Bird類便可。從這裏能夠看出,繼承是一個 "是否是"的關係,而 接口 實現則是 "有沒有"的關係。若是一個類繼承了某個抽象類,則子類一定是抽象類的種類,而接口實現則是有沒有、具有不具有的關係,好比鳥是否能飛(或者是否具有飛行這個特色),能飛行則能夠實現這個接口,不能飛行就不實現這個接口。
2)設計層面不一樣,抽象類做爲不少子類的父類,它是一種模板式設計。而接口是一種行爲規範,它是一種輻射式設計。什麼是模板式設計?最簡單例子,你們都用過ppt裏面的模板,若是用模板A設計了ppt B和ppt C,ppt B和ppt C公共的部分就是模板A了,若是它們的公共部分須要改動,則只須要改動模板A就能夠了,不須要從新對ppt B和ppt C進行改動。而輻射式設計,好比某個電梯都裝了某種報警器,一旦要更新報警器,就必須所有更新。也就是說對於抽象類,若是須要添加新的方法,能夠直接在抽象類中添加具體的實現,子類能夠不進行變動;而對於接口則不行,若是接口進行了變動,則全部實現這個接口的類都必須進行相應的改動。
下面看一個網上流傳最普遍的例子:門和警報的例子:門都有open( )和close( )兩個動做,此時咱們能夠定義經過抽象類和接口來定義這個抽象概念:
abstract class Door { public abstract void open(); public abstract void close(); }
或者:
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接口。
interface Alram { void alarm(); } abstract class Door { void open(); void close(); } class AlarmDoor extends Door implements Alarm { void oepn() { //.... } void close() { //.... } void alarm() { //.... } }