在瞭解抽象類以前,先來了解一下抽象方法。抽象方法是一種特殊的方法:它只有聲明,而沒有具體的實現。抽象方法的聲明格式爲:html
abstract void fun();
抽象方法必須用abstract關鍵字進行修飾。 若是一個類含有抽象方法,則稱這個類爲抽象類,抽象類必須在類前用abstract關鍵字修飾。由於抽象類中含有無具體實現的方法,因此不能用抽象類建立對象。
下面要注意一個問題:在《JAVA編程思想》一書中,將抽象類定義爲「包含抽象方法的類」,可是後面發現若是一個類不包含抽象方法,只是用abstract修飾的話也是抽象類。也就是說抽象類不必定必須含有抽象方法。我的以爲這個屬於鑽牛角尖的問題吧,由於若是一個抽象類不包含任何抽象方法,爲什麼還要設計爲抽象類?因此暫且記住這個概念吧,沒必要去深究爲何。java
public abstract class ClassName { abstract void fun(); }
從這裏能夠看出,抽象類就是爲了繼承而存在的,若是你定義了一個抽象類,卻不去繼承它,那麼等於白白建立了這個抽象類,由於你不能用它來作任何事情。對於一個父類,若是它的某個方法在父類中實現出來沒有任何意義,必須根據子類的實際需求來進行不一樣的實現,那麼就能夠將這個方法聲明爲abstract方法,此時這個類也就成爲abstract類了。編程
包含抽象方法的類稱爲抽象類,但並不意味着抽象類中只能有抽象方法,它和普通類同樣,一樣能夠擁有成員變量和普通的成員方法。ide
抽象類和普通類的主要有三點區別:函數
1)抽象方法必須爲public或者protected(由於若是爲private,則不能被子類繼承,子類便沒法實現該方法),缺省狀況下默認爲public。2)抽象類不能用來建立對象;spa
3)若是一個類繼承於一個抽象類,則子類必須實現父類的抽象方法。若是子類沒有實現父類的抽象方法,則必須將子類也定義爲爲abstract類。線程
在其餘方面,抽象類和普通的類並無區別。設計
接口,英文稱做interface,在軟件工程中,接口泛指供別人調用的方法或者函數。從這裏,咱們能夠體會到Java語言設計者的初衷,它是對行爲的抽象。
在Java中,定一個接口的形式以下:code
public interface InterfaceName { }
接口中能夠含有變量和方法。可是要注意,接口中的變量會被隱式地指定爲public static final變量(而且只能是public static final變量,用private修飾會報編譯錯誤),而方法會被隱式地指定爲public abstract方法且只能是public abstract方法(用其餘關鍵字,好比private、protected、static、 final等修飾會報編譯錯誤),而且接口中全部的方法不能有具體的實現,也就是說,接口中的方法必須都是抽象方法。從這裏能夠隱約看出接口和抽象類的區別,接口是一種極度抽象的類型,它比抽象類更加「抽象」,而且通常狀況下不在接口中定義變量。htm
要讓一個類遵循某組特意的接口須要使用implements關鍵字,具體格式以下:
class ClassName implements Interface1,Interface2,[....]{ }
能夠看出, 容許一個類遵循多個特定的接口。若是一個非抽象類遵循了某個接口,就必須實現該接口中的全部方法。對於遵循某個接口的抽象類,能夠不實現該接口中的抽象方法。
1)抽象類能夠提供成員方法的實現細節,而接口中只能存在public abstract 方法;2)抽象類中的成員變量能夠是各類類型的,而接口中的成員變量只能是public static final類型的;
3)接口中不能含有靜態代碼塊以及靜態方法,而抽象類能夠有靜態代碼塊和靜態方法;
4)一個類只能繼承一個抽象類,而一個類卻能夠實現多個接口。
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接口。
void alarm(); } abstract class Door { void open(); void close(); } class AlarmDoor extends Door implements Alarm { void oepn() { //.... } void close() { //.... } void alarm() { //.... } }
以線程池的例子來講明接口、抽象類以及類在繼承和現實時須要注意的事項
1.接口繼承接口(接口不能實現接口)
Executor是線程池的頂層接口,只有一個方法
public interface Executor { void execute(Runnable command); }
public interface ExecutorService extends Executor { <strong> // <span style="font-family: Verdana, Arial, Helvetica, sans-serif;">ExecutorService 接口繼承自接口Executor</span></strong> void shutdown(); boolean isShutdown(); boolean isTerminated(); boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException; <T> Future<T> submit(Callable<T> task); }
2.抽象類實現接口(抽象類不能繼承接口)
<pre name="code" class="java">public abstract class AbstractExecutorService implements ExecutorService { <strong> // AbstractExecutorService 實現ExecutorService接口,不須要實現ExecutorService接口的方法,由於接口能夠看作一種特殊的抽象類 // 抽象類裏邊的普通方法必須包含方法體,即必須有{},而抽象方法不能有方法體,必須用abstract聲明。</strong> protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { }; protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { }; public Future<?> submit(Runnable task) {}; public <T> Future<T> submit(Runnable task, T result) { }; public <T> Future<T> submit(Callable<T> task) { }; private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks, boolean timed, long nanos) throws InterruptedException, ExecutionException, TimeoutException { }; }
3.普通類繼承抽象類或實現接口
普通類繼承抽象類:必須實現抽象類的全部抽象方法和該抽象類父類的全部方法 普通類實現接口:必須實現接口及其父接口的所有方法
public interface A{ void a(); } public interface B extends A{ void b(); } public abstract class C implements B{ void c(){}; abstract void c1(); } class D extends C{ @Override public void b() { // TODO Auto-generated method stub } @Override public void a() { // TODO Auto-generated method stub } @Override void c1() { // TODO Auto-generated method stub } } class E implements B{ @Override public void a() { // TODO Auto-generated method stub } @Override public void b() { // TODO Auto-generated method stub } }
請尊重做者勞動成果,轉載請標明原文連接 http://www.cnblogs.com/dolphi...