Java 抽象類和接口的區別

1.概述

一個軟件設計的好壞,我想很大程度上取決於它的整體架構,而這個整體架構其實就是你對整個宏觀商業業務的抽象框架,當代表業務邏輯的高層抽象層結構 合理時,你底層的具體實現需要考慮的就僅僅是一些算法和一些具體的業務實現了。當你需要再開發另一個相近的項目時,你以前的抽象層說不定還可以再次利用 。面對對象的設計,複用的重點其實應該是抽象層的複用,而不是具體某一個代碼塊的複用

說到了抽象,我就不能不提到曾讓我頭痛的Java接口和Java抽象類了,這也是本文我想說的重點。

既然面向對象設計的重點在於抽象,那Java接口和Java抽象類就有它存在的必然性了。

Java接口(interface)和Java抽象類(abstract class)代表的就是抽象類型,就是我們需要提出的抽象層的具體表現。OOP面向對象的編程,如果要提高程序的複用率,增加程序 的可維護性,可擴展性,就必須是面向接口的編程,面向抽象的編程,正確地使用接口、抽象類這些有用的抽象類型作爲你結構層次上的頂層。

Java接口和Java抽象類有太多相似的地方,又有太多特別的地方,究竟在什麼地方,纔是它們的最佳位置呢?把它們比較一下,你就可以發現了。

  1. Java接口和Java抽象類最大的一個區別,就在於Java抽象類可以提供某些方法的部分實現,而Java接口不可以(就是interface中只能定義方法,而不能有方法的實現,而在abstract class中則可以既有方法的具體實現,又有沒有具體實現的抽象方法),這大概就是Java抽象類唯一的優點吧,但這個優點非常有用。如果向一個抽象類里加入一個新的具體方法時,那麼它所有的子類都一下子都得到了這個新方法,而Java接口做不到這一點,如果向一個Java接口裏加入一個 新方法,所有實現這個接口的類就無法成功通過編譯了,因爲你必須讓每一個類都再實現這個方法才行,這顯然是Java接口的缺點這個在我的另外一篇博客mapreduce 新舊API 區別中有提到類似的問題,在新的mapreduce api中更傾向於使用抽象類,而不是接口,因爲這更容易擴展。原因就是上面劃線部分所說的。
  2. 一個抽象類的實現只能由這個抽象類的子類給出,也就是說,這個實現處在抽象類所定義出的繼承的等級結構中,而由於Java語言的單繼承性,所以抽象類作爲類型定義工具的效能大打折扣。在這一點上,Java接口的優勢就出來了,任何一個實現了一個Java接口所規定的方法的類都可以具有這個接口的類型,而一個類可以實現任意多個Java接口,從而這個類就有了多種類型。(使用抽象類,那麼繼承這個抽象類的子類類型就比較單一,因爲子類只能單繼承抽象類;而子類能夠同時實現多個接口,因爲類型就比較多。接口和抽象類都可以定義對象,但是隻能用他們的具體實現類來進行實例化。)
  3. 從第2點不難看出,Java接口是定義混合類型的理想工具,混合類表明一個類不僅僅具有某個主類型的行爲,而且具有其他的次要行爲。
  4. 結合1、2點中抽象類和Java接口的各自優勢,具精典的設計模式就出來了:聲明類型的工作仍然由Java接口承擔,但是同時給出一個Java 抽象類,且實現了這個接口,而其他同屬於這個抽象類型的具體類可以選擇實現這個Java接口,也可以選擇繼承這個抽象類,也就是說在層次結構中,Java 接口在最上面,然後緊跟着抽象類,這下兩個的最大優點都能發揮到極至了。這個模式就是“缺省適配模式”。在Java語言API中用了這種模式,而且全都遵循一定的命名規範:Abstract +接口名。(A extends AbstractB implements interfaceC,那麼A即可以選擇實現(@Override)接口interfaceC中的方法,也可以選擇不實現;A即可以選擇實現(@Override)抽象類AbstractB中的方法,也可以選擇不實現)

Java接口和Java抽象類的存在就是爲了用於具體類的實現和繼承的,如果你準備寫一個具體類去繼承另一個具體類的話,那你的設計就有很大問題了。Java抽象類就是爲了繼承而存在的,它的抽象方法就是爲了強制子類必須去實現的。

使用Java接口和抽象Java類進行變量的類型聲明、參數是類型聲明、方法的返還類型說明,以及數據類型的轉換等。而不要用具體Java類進行變量的類型聲明、參數是類型聲明、方法的返還類型說明,以及數據類型的轉換等。

2.實例

下面給出一個具體的接口Action,代碼如下所示:

  1. package org.springframework.webflow.execution;  
  2. public interface Action {  
  3.     public Event execute(RequestContext context) throws Exception;  
  4. }  
在這個接口中,定義了一個沒有具體實現的方法,方法名叫做execute(),返回類型是Event。如前面第一條所述,接口中的方法都是沒有實現的。這些方法的具體實現是在實現(implements)這個接口的類中給出的。

再來看一個實現Action接口的抽象類AbstractAction,代碼如下。

  1. package org.springframework.webflow.action;  
  2.   
  3. import org.apache.commons.logging.Log;  
  4. import org.apache.commons.logging.LogFactory;  
  5. import org.springframework.beans.factory.BeanInitializationException;  
  6. import org.springframework.beans.factory.InitializingBean;  
  7. import org.springframework.util.ClassUtils;  
  8. import org.springframework.webflow.core.collection.AttributeMap;  
  9. import org.springframework.webflow.execution.Action;  
  10. import org.springframework.webflow.execution.Event;  
  11. import org.springframework.webflow.execution.RequestContext;  
  12.   
  13. public abstract class AbstractAction implements Action, InitializingBean {  
  14.   
  15.     protected final Log logger = LogFactory.getLog(getClass());  
  16.   
  17.     public EventFactorySupport getEventFactorySupport() {  
  18.         return new EventFactorySupport();  
  19.     }  
  20.   
  21.     public void afterPropertiesSet() throws Exception {  
  22.         try {  
  23.             initAction();  
  24.         } catch (Exception ex) {  
  25.             throw new BeanInitializationException("Initialization of this Action failed: " + ex.getMessage(), ex);  
  26.         }  
  27.     }  
  28.   
  29.     protected void initAction() throws Exception {  
  30.     }  
  31.   
  32.     protected Event success() {  
  33.         return getEventFactorySupport().success(this);  
  34.     }  
  35.   
  36.     protected Event success(Object result) {  
  37.         return getEventFactorySupport().success(this, result);  
  38.     }  
  39.   
  40.     protected Event error() {  
  41.         return getEventFactorySupport().error(this);  
  42.     }  
  43.   
  44.     protected Event error(Exception e) {  
  45.         return getEventFactorySupport().error(this, e);  
  46.     }  
  47.   
  48.     protected Event yes() {  
  49.         return getEventFactorySupport().yes(this);  
  50.     }  
  51.   
  52.     protected Event no() {  
  53.         return getEventFactorySupport().no(this);  
  54.     }  
  55.   
  56.     protected Event result(boolean booleanResult) {  
  57.         return getEventFactorySupport().event(this, booleanResult);  
  58.     }  
  59.   
  60.     protected Event result(String eventId) {  
  61.         return getEventFactorySupport().event(this, eventId);  
  62.     }  
  63.   
  64.     protected Event result(String eventId, AttributeMap resultAttributes) {  
  65.         return getEventFactorySupport().event(this, eventId, resultAttributes);  
  66.     }  
  67.   
  68.     protected Event result(String eventId, String resultAttributeName, Object resultAttributeValue) {  
  69.         return getEventFactorySupport().event(this, eventId, resultAttributeName, resultAttributeValue);  
  70.     }  
  71.   
  72.     public final Event execute(RequestContext context) throws Exception {  
  73.         Event result = doPreExecute(context);  
  74.         if (result == null) {  
  75.             result = doExecute(context);  
  76.             doPostExecute(context);  
  77.         } else {  
  78.             if (logger.isInfoEnabled()) {  
  79.                 logger.info("Action execution disallowed; pre-execution result is '" + result.getId() + "'");  
  80.             }  
  81.         }  
  82.         return result;  
  83.     }  
  84.   
  85.     protected String getActionNameForLogging() {  
  86.         return ClassUtils.getShortName(getClass());  
  87.     }  
  88.   
  89.     protected Event doPreExecute(RequestContext context) throws Exception {  
  90.         return null;  
  91.     }  
  92.   
  93.     //抽象方法  
  94.     protected abstract Event doExecute(RequestContext context) throws Exception;  
  95.   
  96.     protected void doPostExecute(RequestContext context) throws Exception {  
  97.     }  
  98. }  
在抽象類AbstractAction中,既有具體實現的方法,又有沒有具體實現的抽象方法
  1. //抽象方法  
  2. protected abstract Event doExecute(RequestContext context) throws Exception;  
需要注意的是在抽象類中,如果方法沒有具體實現(就是方法後面沒有{}),那麼必須加上abstract來聲明這個方法,而接口中不需要使用abstract來聲明(抽象類之所以被稱爲抽象類,就是因爲它包含有抽象方法。含有抽象方法的類叫做抽象類)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章