天天看點

深入分析java抽象類與接口差別

對于很多開發者來說,抽象類與接口的選擇都很模糊,也有很多開發人員壓根就不使用他們。你或許會說,隻要實作功能就行,我甚至都不适用任何架構都可以寫出來。當然,每個開發人員都是獨立的個體,都有自己獨特的想法,尤其是java程式設計行業。會定義變量,會建立對象,會程式流程等一些基本知識的了解都可以上手開發項目,如果你是這麼認為的,那麼請選擇關閉這篇文章。

1、什麼是抽象類

通俗的将就是這個類是被迫這樣子的,兒子欠别人的錢,老子不能不還呀!因為該類中肯定存在抽象方法,是以我必須是抽象類。如果還跟普通的類一樣的話,我存在的價值就展現不出來了。

有抽象方法的類肯定是抽象類,那麼抽象類中肯定有抽象方法嗎?(當然不是,老子是個窮光蛋,不一定兒子就是個窮光蛋。)

抽象類中除了有特定的抽象方法之外,跟普通類沒有多大的差別,可以有自己的屬性和方法。

public abstract class Car {

    /**
     * 該方法是一個抽象方法
     * 抽象方法隻有定義,沒有實作
     * 同樣因為抽象類中有沒有實作的方法,是以抽象類時不可能建立某一個具體的對象的
     */
    public abstract void move();
    /**
     * 可以定義普通的方法
     */
    public void open(){
        
        System.out.println("------汽車可以開------");
    }
    /**
     * 也可以定義自己的屬性
     */
    private String name;
    private int speed;
    
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }
    
    public static void main(String[] args) {
        
    }
}
           

有的人會問:什麼是抽象方法呢?簡單了解就是,你隻是知道我的名字,卻不知道我具體是幹什麼的。抽象方法是一種特殊的方法:它隻有聲明,而沒有具體的實作。

與普通方法的差別就是,abstract。

因為抽象類中含有沒有實作的抽象方法,是以是不可能new出來對象的,是不可能有自己的對象的。要不又跟普通類一樣。

簡單一句話:就因為有一個沒有實作的方法,所有java才會給這一個特性起名為抽象。這個特殊的方法産生了,我們就要想辦法去管理它,所有就産生了抽象類。抽象類如果可以自己定義對象的話,那跟普通的類不一樣了嗎?是以抽象類它才會産生這個不能定義自己對象的特性。

1)抽象方法必須是public或者protected,因為如果是private子類是不可能去繼承,也會存在實作功能。

2)抽象類不能用來建立對象;

3)如果一個類繼承于一個抽象類,則子類必須實作父類的抽象方法。如果子類沒有實作父類的抽象方法,則必須将子類也定義為為abstract類。

在其他方面,抽象類和普通的類并沒有差別。

2、什麼是接口。

接口,英文稱作interface,在軟體工程中,接口泛指供别人調用的方法或者函數。從這裡,我們可以體會到Java語言設計者的初衷,它是對行為的抽象。

在Java中,定一個接口的形式如下:

接口中可以含有 變量和方法。但是要注意,接口中的變量會被隐式地指定為public static final變量(并且隻能是public static final變量,用private修飾會報編譯錯誤),而方法會被隐式地指定為public abstract方法且隻能是public abstract方法(用其他關鍵字,比如private、protected、static、 final等修飾會報編譯錯誤),并且接口中所有的方法不能有具體的實作,也就是說,接口中的方法必須都是抽象方法。

從這裡可以隐約看出接口和抽象類的差別,接口是一種極度抽象的類型,它比抽象類更加“抽象”,并且一般情況下不在接口中定義變量。

接口是抽象類的抽象。

3、他們兩者之間的差別。

3.1、java文法上面差別;

     1)抽象類中的屬性和方法可以是任意類型的,接口中的屬性和方法預設是抽象的。

     2)抽象類中的方法包含靜态代碼塊和靜态方法,接口中是不允許的。

     3)一個類隻能繼承一個抽象類,而一個類卻可以實作多個接口。

3.2、java設計層面上的差別。

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( )兩個動作,此時我們可以定義通過抽象類和接口來定義這個抽象概念:

1 2 3 4

abstract

class

Door {

public

abstract

void

open();

public

abstract

void

close();

}

或者:

1 2 3 4

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接口。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

interface

Alram {

void

alarm();

}

abstract

class

Door {

void

open();

void

close();

}

class

AlarmDoor

extends

Door

implements

Alarm {

void

oepn() {

//....

}

void

close() {

//....

}

void

alarm() {

//....

}

}