抽象类与接口关系
來源:?http://blog.xiaohansong.com/2015/12/02/abstract-class-and-interface/
- 抽象類和接口的對比
- 從 java 容器類的設計討論抽象類和接口的應用
- 抽象類和接口的使用時機
抽象類與接口的對比
| 默認的方法實現 | 它可以有默認的方法實現 | 接口完全是抽象的。它根本不存在方法的實現 | ? | 
| 實現 | 子類使用extends關鍵字來繼承抽象類。如果子類不是抽象類的話,它需要提供抽象類中所有聲明的方法的實現。 | 子類使用關鍵字implements來實現接口。它需要提供接口中所有聲明的方法的實現 | |
| 構造器 | 抽象類可以有構造器 | 接口不能有構造器 | |
| 與正常Java類的區別 | 除了你不能實例化抽象類之外,它和普通Java類沒有任何區別 | 接口是完全不同的類型 | |
| 訪問修飾符 | 抽象方法可以有public、protected和default這些修飾符 | 接口方法默認修飾符是public。你不可以使用其它修飾符。 | |
| main方法 | 抽象方法可以有main方法并且我們可以運行它 | 接口沒有main方法,因此我們不能運行它。 | |
| 多繼承 | 抽象方法可以繼承一個類和實現多個接口 | 接口只可以繼承一個或多個其它接口 | |
| 速度 | 它比接口速度要快 | 接口是稍微有點慢的,因為它需要時間去尋找在類中實現的方法。 | |
| 添加新方法 | 如果你往抽象類中添加新的方法,你可以給它提供默認的實現。因此你不需要改變你現在的代碼。 | 如果你往接口中添加方法,那么你必須改變實現該接口的類。 | 
抽象類和接口有不同,也有相似的地方。有些書把接口稱作特殊的類,雖然不準確,但也有一定道理,接口能做的事情,抽象類也能做到,除了多重繼承。正是因為這些相似的特性,讓我們在使用它們的時候有了困惑:這里到底該用抽象類還是接口?
從 java 容器類的設計討論抽象類和接口的應用
除了前面提到的一個問題:多態到底是用抽象類還是接口實現?我還看到有人評論說:現在都是提倡面向接口編程,使用抽象類的都被稱為上世紀的老碼農了。哈哈。看到這個說法我也是苦笑不得。不過,面向接口編程的確是一個趨勢,java 8 已經支持接口實現默認方法和靜態方法了,抽象類和接口之間的差異越來越小。閑話少說,我們開始討論抽象類和接口的應用。
full_container_taxonomy
上圖是 java 容器類的類繼承關系。我們以容器類中?ArrayList?為例子來討論抽象類和接口的應用。
ArrayList 類繼承關系
ArrayList
上圖是?ArrayList?的類繼承關系。可以看到,ArrayList?的繼承關系中既使用了抽象類,也使用了接口。
- 最頂層的接口是?Iterable,表示這是可迭代的類型。所有容器類都是可迭代的,這是一個極高的抽象。
- 第二層的接口是?Collection,這是單一元素容器的接口。集合,列表都屬于此類。
- 第三層的接口是?List,這是所有列表的接口。
通過三個接口,我們可以找到容器類的三個抽象特性,實現這些接口就意味著擁有這些接口的特性。
- AbstractCollection?實現了?Collection?中的部分方法。
- AbstractList?實現了?AbstractCollection?和?List?中的部分方法。
上面的抽象類提供了一些方法的默認實現,給具體類提供了復用代碼。
純抽象類實現
如果我們像一個老碼農一樣,用抽象類來實現上面的接口會有怎樣的效果?那么,類圖可能變成這樣。
AbtractList
抽象類在這里存在著一個很大的問題,它不能多繼承,在抽象的層次上沒有接口高,也沒有接口靈活。例如說:
List + AbstractCollection -> AbstractList Set + AbstractCollection -> AbstractSet單純用抽象類無法實現像接口一樣靈活的擴展。
純接口實現
如果我們像一個新碼農一樣,用純接口來實現呢?
InterfaceList
這樣寫理論上沒有問題,實際寫代碼的時候問題就來了。所有的接口都要提供實現,于是你不得不在各個實現類中重復代碼。
總結
經過上面的討論,我們得出兩個結論:
- 抽象類和接口并不能互相替代。
- 抽象類和接口各有不可替代的作用。
從容器類的類關系圖中可以看到,接口主要是用來抽象類型的共性,例如說,容器的可迭代特性。抽象類主要是給具體實現類提供重用的代碼,例如說,List?的一些默認方法。
抽象類和接口的使用時機
那么,什么時候該用抽象類,什么時候該用接口呢?
要解決上面的問題,我們先從弄清楚抽象類和接口之間的關系。首先,我們都知道類對事物的抽象,定義了事物的屬性和行為。而抽象類是不完全的類,具有抽象方法。接口則比類的抽象層次更高。所以,我們可以這樣理解它們之間的關系:類是對事物的抽象,抽象類是對類的抽象,接口是對抽象類的抽象。
從這個角度來看 java 容器類,你會發現,它的設計正體現了這種關系。不是嗎?從?Iterable?接口,到?AbstractList?抽象類,再到?ArrayList?類。
現在回答前面的問題:在設計類的時候,首先考慮用接口抽象出類的特性,當你發現某些方法可以復用的時候,可以使用抽象類來復用代碼。簡單說,接口用于抽象事物的特性,抽象類用于代碼復用。
當然,不是所有類的設計都要從接口到抽象類,再到類。程序設計本就沒有絕對的范式可以遵循。上面的說法只是提供一個角度來理解抽象類和接口的關系,每個人都會有自己的理解,有人認為兩者一點關系都沒有,這也有道理。總之,模式和語法是死的,人是活的。
?
來源:?http://blog.xiaohansong.com/2015/12/02/abstract-class-and-interface/轉載于:https://www.cnblogs.com/tuanz/p/8709021.html
總結
 
                            
                        