首頁>技術>

介面

官方對於介面的解釋是一系列方法的宣告,是一些方法特徵的集合。那麼我們就根據這句話聊一聊介面的特徵。

首先從上面這句話可以看出介面中定義了一系列方法的宣告,而沒有方法的實現,那麼從這個角度來看介面就是一種規則的制定者,它不關心你如何實現,只是約束你必須具備這些行為,符合這些規則。而我們的方法中需要定義了一系列業務邏輯程式碼,完成各種特定的行為,因此方法就是行為在系統中的一種表現形式,而介面約束了我們必須具備哪些行為,那麼總結一句話,介面就是對行為的抽象。

比如公司介面規定人應該具備加班的行為(手動調皮),不加班是不行的,總不能不提倡奮鬥吧。那麼不同的人可能透過不同的方式完成這種行為,有的人可能完成工作快一點,有的人可能完成工作慢一點,有的人手頭任務多一點,有的人手頭任務少一點,介面對行為進行了抽象,先不關心你到底幹了什麼,但你必須具備加班這種行為。

抽象類

抽象類直觀來看就是對類的抽象,而我們又知道類是對同屬於一個類的所有物件的抽象,Java是一門面向物件的程式設計語言,它將現實世界的客觀事物抽象為物件,因此我們又知道物件是對現實世界的客觀事物的抽象。那麼總結一句話,抽象類是對類的抽象,是對現實世界的客觀事物的進一步抽象。

介面與抽象類的比較

這個問題應該是經常被問到的一個問題,筆者認為我們可以從三個角度來對二者進行比較:(1)類(2)屬性(3)方法

從類的角度一個類要使用抽象類需要使用extends關鍵字,也就是需要繼承抽象類,並且由於Java是單繼承,所以只能繼承一個抽象類。一個類要使用介面需要使用implements關鍵字,稱為實現該介面,同時由於Java是多實現機制,所以可以實現多個介面。抽象類與介面均不能例項化,也就是不能創造介面或者抽象類物件。從屬性的角度

首先我們看以下程式碼

abstract class AbstractClass{    private int a;//可以    int b;//可以    protected int c;//可以    public int d;//可以    private final int e=1;//可以    private static int f=2;//可以    private static final int g=3;//可以}interface  Interface{    private int a=1;//不可以    int b;//不可以    int c=1;//可以    protected int d=2;//不可以;    public int e=3;//可以    public  static int f=4;//可以    public static final int g=5;//可以}複製程式碼

從上面的程式碼我們可以看出

在抽象類中定義屬性與普通的類定義屬性沒有任何的區別,定義類的屬性如何定義,抽象類的屬性就可以如何定義。在介面中我們只能使用不帶任何修飾符,帶public ,帶static,帶final這幾個修飾符,實際上透過反編譯之後可以看到介面中的屬性全部是使用public static final修飾的。也就是說介面中定義的屬性就是以常量的形式存在。從方法的角度

方法的角度應該抽象類與介面之間差別最大的地方,尤其是現在各個版本都在對介面中的方法不斷的進行改變,這裡以JDK1.8為例,比較一下介面與抽象類中的方法具有哪些差別。

存在抽象方法的類一定是抽象類,但是抽象類並不需要全部是抽象方法,也可以有普通方法,甚至全部是普通方法(不過如何沒有抽象方法,又為何要定義成抽象類呢?)對於抽象類中的普通方法,定義與普通的類中的方法定義一致,可以使用private,不修飾,protected,public 修飾。對於抽象方法,不可以使用private修飾(因為抽象方法本身就是需要子類繼承重寫的)。普通方法可以使用static修飾,抽象方法不可以使用static修飾。介面中的方法可以不使用修飾符,或者使用public修飾,透過反編譯之後可知,介面中的方法都是用public abstract修飾的,這與介面中的屬性類似。不同的是在JDK1.8中,介面可以定義靜態方法與default方法,並需要給出預設實現。二者如何配合使用

我們學習抽象類與介面,最終都是為了能夠更好的使用抽象類與介面為我們服務,二者沒有孰好孰壞,孰強孰弱,如果是這樣的話那其中一個就沒有存在的必要了,我們需要學習的是如何讓兩者配合使用,我們可以從Java世界大量的程式碼與第三方框架中思考這一點。

而抽象類前面我們說是對類的抽象,其設計目的,筆者認為更重要的一方面在於程式碼的複用,另一方面在於減輕介面實現的負擔。當不同的類具備了其中的某些公共的行為,並且這種行為的實現方式一致的時候,這時我們就可以讓這些類派生於一個抽象類,避免所有的子類都需要實現介面中的全部方法,這樣就實現了程式碼的複用,同時降低了類實現介面的負擔(不需要實現全部介面方法)。

一個例子

現在我們對現實世界中的小車車進行抽象,透過一個例子想一下抽象類與介面可以如何配合使用?

1、首先小車車應該可以行駛,同時需要能量驅動發動機行進,可以開門,可以關門。這樣我們將小車車的四個行為抽象為介面中的方法,因為這些方法是所有的小車車都必須具備的。

interface Car{    //行進    public void move();    //補充能量    public void addEnergy();    //開門    public void openTheDoor();    //關門    public void closeTheDoor();}複製程式碼

2、這樣我們在造小車車的時候,首先必須要實現這四個行為,也就是要實現這四個功能,但是每造一種小車車就需要實現這些功能,各種小車車之間是存在很多差異的,但是這些基本的功能實現都是相似的或者相同的,那這個時候我們想到現在的小車車可以分為燃油車與電車,那麼我們可以抽象一下實現這些方法。這樣可以降低造小車車的負擔(降低實現介面的負擔),提高程式碼的複用率。

abstract class AbstractFuelCar implements Car{    public void move()    {        System.out.println("油車突突突的向前衝!!!");    }    public void addEnergy()    {        System.out.println("加油。。。");        //呼叫子類重寫的加油方法。        refuel();    }    public void openTheDoor()    {        System.out.println("燃油車開門。。。");    }    public void closeTheDoor()    {        System.out.println("燃油車關門。。。");    }    public abstract void refuel();}abstract class AbstractEnergyCar implements Car{    public void move()    {        System.out.println("電車滋滋滋的向前衝!!!");    }    public void addEnergy()    {        System.out.println("加電。。。");        //呼叫子類重寫的加油方法。        charge();    }    public void openTheDoor()    {        System.out.println("電車開門。。。");    }    public void closeTheDoor()    {        System.out.println("電車關門。。。");    }    public abstract void charge();}複製程式碼

3、我們在造具體的小車車的時候,只需要繼承對應的抽象類實現模板方法以及一些每種小車車特有的功能方法即可,這樣不但提高了程式碼複用,同樣也降低了實現介面的負擔。

class BMW extends AbstractFuelCar{    @Override    public void refuel()    {        System.out.println("BMW加油了!!!!");    }    public void someOtherFunction()    {        System.out.println("我有點小貴。。。");    }}class Tesla extends  AbstractEnergyCar{    @Override    public void charge()    {        System.out.println("特斯拉充電了。。。。");    }    public void someOtherFunction()    {        System.out.println("俺加速快!!!");    }}複製程式碼

所以一般介面用於規定業務邏輯應該實現什麼樣的功能,具備什麼樣的行為,而抽象類在介面之下主要用於程式碼複用,抽取一些公共行為,降低實現介面的負擔,透過模板方法圈定業務邏輯流程,降低子類的實現複雜度。如下圖所示:

在Java世界裡學習

下面我們看一下Java類庫中以及一些常用的第三方開源框架中是如何配合使用介面與抽象類的。

1、StringBuilder與StringBuffer

StringBuilder與StringBuffer的繼承結構如下所示:

2、Java中集合框架

ArrayList

HashMap

3、執行緒池ThreadPoolExecutor

4、第三方開源框架

Spring中的BeanFactory實現類,ApplicationContext實現類,BeanPostProcessor,AOP方面PointCutAdvisor實現等,SpringJDBC,事務管理,SpringMVC,MyBatis中SqlSession等有大量的這樣的結構,由於其繼承結構一般都比較複雜,這裡不再附上圖片,感興趣的同學可以檢視Spring,MyBatis等框架的相關原始碼。

27
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 寫了個 Android 效能檢測的庫,還有人看效能相關的麼?