C語言中文網 目錄

Java接口和抽象類的區別

從前面對面向對象的設計原則的講解,讀者可以了解到,其實所有的設計原則和設計模式都離不開抽象,因為只有抽象才能實現上述設計原則和設計模式。

Java 中,針對抽象有兩種實現方式:一種是接口,一種是抽象類。很多讀者對這兩種實現方式比較困惑,到底是使用接口,還是使用抽象類呢?對于它們的選擇甚至反映出對問題領域本質的理解,對設計意圖的理解是否正確、合理?

在面向對象的設計思想中,所有的對象都是通過類來描繪的,但是反過來,并不是所有的類都是用來描繪對象的,如果一個類中沒有描繪一個具體的對象,那么這樣的類就是抽象類,抽象類是對那些看上去不同,但是本質上相同的具體概念的抽象,正是因為抽象的概念在問題領域沒有對應的具體概念,所以抽象類是不能夠實例化的。

基本語法區別

在 Java 中,接口和抽象類的定義語法是不一樣的。這里以動物類為例來說明,其中定義接口的示意代碼如下:
public interface Animal
{
    //所有動物都會吃
    public void eat();

    //所有動物都會飛
    public void fly();
}

定義抽象類的示意代碼如下:
public abstract class Animal
{
    //所有動物都會吃
    public abstract void eat();

    //所有動物都會飛
    public void fly(){};
}

可以看到,在接口內只能是功能的定義,而抽象類中則可以包括功能的定義和功能的實現。在接口中,所有的屬性肯定是 public、static 和 final,所有的方法都是 abstract,所以可以默認不寫上述標識符;在抽象類中,既可以包含抽象的定義,也可以包含具體的實現方法。

在具體的實現類上,接口和抽象類的實 現類定義方式也是不一樣的,其中接口實現類的示意代碼如下:
public class concreteAnimal implements Animal
{
    //所有動物都會吃
    public void eat(){}

    //所有動物都會飛
    public void fly(){}
}

抽象類的實現類示意代碼如下:
public class concreteAnimal extends Animal
{
    //所有動物都會吃
    public void eat(){}

    //所有動物都會飛
    public void fly(){}
}

可以看到,在接口的實現類中使用 implements 關鍵字;而在抽象類的實現類中,則使用 extends 關鍵字。一個接口的實現類可以實現多個接口,而一個抽象類的實現類則只能實現一個抽象類。

設計思想區別

從前面抽象類的具體實現類的實現方式可以看出,其實在 Java 中,抽象類和具體實現類之間是一種繼承關系,也就是說如果釆用抽象類的方式,則父類和子類在概念上應該是相同的。接口卻不一樣,如果采用接口的方式,則父類和子類在概念上不要求相同。接口只是抽取相互之間沒有關系的類的共同特征,而不用關注類之間的關系,它可以使沒有層次關系的類具有相同的行為。因此,可以這樣說:抽象類是對一組具有相同屬性和方法的邏輯上有關系的事物的一種抽象,而接口則是對一組具有相同屬性和方法的邏輯上不相關的事物的一種抽象。

仍然以前面動物類的設計為例來說明接口和抽象類關于設計思想的區別,該動物類默認所有的動物都具有吃的功能,其中定義接口的示意代碼如下:
public interface Animal
{
    //所有動物都會吃
    public void eat();
}

定義抽象類的示意代碼如下:
public abstract class Animal
{
    //所有動物都會吃
    public abstract void eat();
}

不管是實現接口,還是繼承抽象類的具體動物,都具有吃的功能,具體的動物類的示意代碼如下。

接口實現類的示意代碼如下:
public class concreteAnimal implements Animal
{
    //所有動物都會吃
    public void eat(){}
}

抽象類的實現類示意代碼如下:
public class concreteAnimal extends Animal
{
    //所有動物都會吃
    public void eat(){}
}

當然,具體的動物類不光具有吃的功能,比如有些動物還會飛,而有些動物卻會游泳,那么該如何設計這個抽象的動物類呢?可以別在接口和抽象類中增加飛的功能,其中定義接口的示意代碼如下:
public interface Animal
{
    //所有動物都會吃
    public void eat();

    //所有動物都會飛
    public void fly();
}

定義抽象類的示意代碼如下:
public abstract class Animal
{
    //所有動物都會吃
    public abstract void eat();

    //所有動物都會飛
    public void fly(){};
}

這樣一來,不管是接口還是抽象類的實現類,都具有飛的功能,這顯然不能滿足要求,因為只有一部分動物會飛,而會飛的卻不一定是動物,比如飛機也會飛。那該如何設計呢?有很多種方案,比如再設計一個動物的接口類,該接口具有飛的功能,示意代碼如下:
public interface AnimaiFly
{
    //所有動物都會飛
    public void fly();
}

那些具體的動物類,如果有飛的功能的話,除了實現吃的接口外,再實現飛的接口,示意代碼如下:
public class concreteAnimal implements Animal,AnimaiFly
{
    //所有動物都會吃
    public void eat(){}

    //動物會飛
    public void fly();
}

那些不需要飛的功能的具體動物類只實現具體吃的功能的接口即可。另外一種解決方案是再設計一個動物的抽象類,該抽象類具有飛的功能,示意代碼如下:
public abstract class AnimaiFly
{
    //動物會飛
    public void fly();
}

但此時沒有辦法實現那些既有吃的功能,又有飛的功能的具體動物類。因為在 Java 中具體的實現類只能實現一個抽象類。一個折中的解決辦法是,讓這個具有飛的功能的抽象類,繼承具有吃的功能的抽象類,示意代碼如下:
public abstract class AnimaiFly extends Animal
{
    //動物會飛
    public void fly();
}

此時,對那些只需要吃的功能的具體動物類來說,繼承 Animal 抽象類即可。對那些既有吃的功能又有飛的功能的具體動物類來說,則需要繼承 AnimalFly 抽象類。

但此時對客戶端有一個問題,那就是不能針對所有的動物類都使用 Animal 抽象類來進行編程,因為 Animal 抽象類不具有飛的功能,這不符合面向對象的設計原則,因此這種解決方案其實是行不通的。

還有另外一種解決方案,即具有吃的功能的抽象動物類用抽象類來實現,而具有飛的功能的類用接口實現;或者具有吃的功能的抽象動物類用接口來實現,而具有飛的功能的類用抽象類實現。

具有吃的功能的抽象動物類用抽象類來實現,示意代碼如下:
public abstract class Animal
{
    //所有動物都會吃
    public abstract void eat();
}

具有飛的功能的類用接口實現,示意代碼如下:
public interface AnimaiFly
{
    //動物會飛
    public void fly();
}

既具有吃的功能又具有飛的功能的具體的動物類,則繼承 Animal 動物抽象類,實現 AnimalFly 接口,示意代碼如下:
public class concreteAnimal extends Animal implements AnimaiFly
{
    //所有動物都會吃
    public void eat(){}

    //動物會飛
    public void fly();
}

或者具有吃的功能的抽象動物類用接口來實現,示意代碼如下:
public interface Animal
{
    //所有動物都會吃
    public abstract void eat();
}

具有飛的功能的類用抽象類實現,示意代碼如下:
public abstract class AnimaiFly
{
    //動物會飛
    public void fly(){};
}

既具有吃的功能又具有飛的功能的具體的動物類,則實現 Animal 動物類接口,繼承 AnimaiFly 抽象類,示意代碼如下:
public class concreteAnimal extends AnimaiFly implements Animal
{
    //所有動物都會吃
    public void eat(){}

    //動物會飛
    public void fly();
}

這些解決方案有什么不同呢?再回過頭來看接口和抽象類的區別:抽象類是對一組具有相同屬性和方法的邏輯上有關系的事物的一種抽象,而接口則是對一組具有相同屬性和方法的邏輯上不相關的事物的一種抽象,因此抽象類表示的是“is a”關系,接口表示的是“like a”關系。

假設現在要研究的系統只是動物系統,如果設計人員認為對既具有吃的功能又具有飛的功能的具體的動物類來說,它和只具有吃的功能的動物一樣,都是動物,是一組邏輯上有關系的事物,因此這里應該使用抽象類來抽象具有吃的功能的動物類,即繼承 Animal 動物抽象類,實現 AnimalFly 接口。

如果設計人員認為對既具有吃的功能,又具有飛的功能的具體的動物類來說,它和只具有飛的功能的動物一樣,都是動物,是一組邏輯上有關系的事物,因此這里應該使用抽象類來抽象具有飛的功能的動物類,即實現 Animal 動物類接口,繼承 AnimaiFly 抽象類。

假設現在要研究的系統不只是動物系統,如果設計人員認為不管是吃的功能,還是飛的功能和動物類沒有什么關系,因為飛機也會飛,人也會吃,則這里應該實現兩個接口來分別抽象吃的功能和飛的功能,即除實現吃的 Animal 接口外,再實現飛的 AnimalFly 接口。

從上面的分析可以看出,對于接口和抽象類的選擇,反映出設計人員看待問題的不同角度,即抽象類用于一組相關的事物,表示的是“isa”的關系,而接口用于一組不相關的事物,表示的是“like a”的關系。

精美而實用的網站,提供C語言、C++、STL、Linux、Shell、Java、Go語言等教程,以及socket、GCC、vi、Swing、設計模式、JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo
极速pk10开户