其實(shí)說實(shí)話,沒有多大的可比較性,它們是完全不同的兩個(gè)東西,它們的抽象不在同一個(gè)層級(jí)上。但是為了讓大家更好的理解,還是做一個(gè)比較吧,畢竟它們都很抽象(233)。
首先是語法層面上的對(duì)比
1)抽象類跟接口都不能被實(shí)例化,因?yàn)樗鼈兌己芴撀铩5窃谠L問權(quán)限上,兩者有一定的區(qū)別。
a、抽象類中的抽象方法(其前有abstract修飾)不能用private、static、synchronized、native訪問修飾符修飾。理由很簡單,容我慢慢道來。
抽象方法是沒有方法體的,它的目的就是用來繼承的,所以如果使用private修飾,不就不能被繼承了嗎?這就違背了它的設(shè)計(jì)初衷了,所以不能用private來修飾抽象方法。至于static,用它來修飾的方法可以不實(shí)例化就可以直接調(diào)用,但是抽象方法沒有方法體,使用static修飾就沒有意義了。synchronized是用來加鎖的,如果修飾類中的方法的話,就相當(dāng)于用this變量鎖,但是抽象類是不能被實(shí)例化的,抽象方法也不是在本類中實(shí)現(xiàn)而是在子類中實(shí)現(xiàn)的,所以鎖應(yīng)該是子類所屬,所以抽象方法不能用synchronized關(guān)鍵字修飾;至于native,這個(gè)跟abstract關(guān)鍵字本身就是沖突的,abstract聲明方法交給子類實(shí)現(xiàn),而native則是交給本地操作系統(tǒng)實(shí)現(xiàn),如果同時(shí)出現(xiàn),那就相當(dāng)于把實(shí)現(xiàn)交給子類,又交給本地操作系統(tǒng),那最后到底由誰來實(shí)現(xiàn)呢?
綜上所述,抽象類中的抽象方法只能用public和protected修飾。
b.接口中的方法全部為public abstract修飾,不能使用其他修飾符,而且默認(rèn)情況(不加任何修飾符)下,也是public abstract的,因?yàn)榻涌谥荒鼙活悓?shí)現(xiàn),不能被類繼承,所以不能使用protected修飾,但接口是可以繼承接口的。
2)抽象類跟普通類的唯一區(qū)別就是不能被實(shí)例化,可以有抽象方法,所以它可以有構(gòu)造函數(shù),靜態(tài)方法,靜態(tài)代碼塊,可以有普通的成員變量和方法。但是接口就不一樣了,接口只能聲明public abstract的方法和public static final的成員變量。
3)抽象類本質(zhì)上還是一個(gè)類,只能單繼承,一個(gè)類只能繼承一個(gè)抽象類,但可以實(shí)現(xiàn)多個(gè)接口。
其次是概念上的比較
1)抽象類跟接口的抽象角度不一樣,抽象類一般是對(duì)某些具有相似屬性和方法的類進(jìn)行抽象,抽象出一個(gè)統(tǒng)一的父類。而接口則更多的是多一組特定行為的抽象,關(guān)注的是行為,而具有這些行為的類之間可能并沒有太大的關(guān)聯(lián)性。
比如說,飛機(jī)能上天,鳥能上天,你要是厲害一點(diǎn),應(yīng)該也能上天(逃),但顯然兩者之間的關(guān)聯(lián)度不大,如果硬是要給它們插上一個(gè)公共的父類的話,似乎不合情理,看起來就像這樣:
1
2
3
|
public abstract class Flyer { public abstract void fly(); } |
然后定義兩個(gè)類來繼承它:
1
2
3
4
5
6
7
|
public class Airplane extends Flyer { @Override public void fly() { System.out.println( "Airplane is flying." ); } } |
1
2
3
4
5
6
7
|
public class Bird extends Flyer { @Override public void fly() { System.out.println( "Bird is flying." ); } } |
好的,現(xiàn)在寫一個(gè)測(cè)試類:
1
2
3
4
5
6
7
8
9
10
|
public class Test { public static void main(String[] args) { Flyer[] flyer = new Flyer[ 2 ]; flyer[ 0 ] = new Airplane(); flyer[ 1 ] = new Bird(); for (Flyer f:flyer){ f.fly(); } } } |
運(yùn)行結(jié)果如下:
Airplane is flying.
Bird is flying.
乍眼一看,好像運(yùn)行良好,但是仔細(xì)想想,將兩個(gè)關(guān)聯(lián)度很低的類強(qiáng)行插上一個(gè)父類,似乎有些不妥,畢竟飛機(jī)跟鳥除了都能飛以外,基本沒有什么相似的地方了,而且兩者的飛行方式,飛行速度和高度都相去甚遠(yuǎn),也就是說除了這個(gè)fly的方法,其他方法都要在各自的子類實(shí)現(xiàn),而且一個(gè)類只能繼承一個(gè)抽象類,所以Bird類和Airplane類就無法再繼承其他類了,這樣就反而限制了程序的靈活性。所以,這種時(shí)候,還是比較適合使用接口:
1
2
3
4
|
public interface IFlyable { //聲明Fly方法 void fly(); } |
而此時(shí)只需要將Airplane類和Bird類的extends Flyer改成implement Flyable即可。
1
2
3
4
5
6
7
8
|
public class Airplane implements IFlyable { //實(shí)現(xiàn)Fly方法 @Override public void fly() { System.out.println( "Airplane is flying." ); } } |
1
2
3
4
5
6
7
|
public class Bird implements IFlyable { //實(shí)現(xiàn)Fly方法 @Override public void fly() { System.out.println( "Bird is flying." ); } } |
再修改一下Test類:
1
2
3
4
5
6
7
8
9
10
|
public class Test { public static void main(String[] args) { IFlyable[] flyer = new IFlyable[ 2 ]; flyer[ 0 ] = new Airplane(); flyer[ 1 ] = new Bird(); for (IFlyable f:flyer){ f.fly(); } } } |
輸出如下:
Airplane is flying.
Bird is flying.
也許從這個(gè)栗子還沒法明顯的看出兩者的區(qū)別,那么我們?cè)贀Q一個(gè)栗子,人可以坐飛機(jī),可以坐火車,還可以坐汽車,只要它們有載人功能即可,那用接口實(shí)現(xiàn)如下:
1
2
3
4
5
|
public interface ICarryPassenger { //聲明載客方法 void carry(Passenger passenger); } |
定義一個(gè)乘客類,用姓名來區(qū)分各個(gè)乘客。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class Passenger { private String name; //乘客姓名 public Passenger(String name){ this .name = name; } public String getName() { return name; } //出行方式 public void travelBy(ICarryPassenger ic){ ic.carry( this ); } } |
分別定義汽車類,火車類,飛機(jī)類,它們都實(shí)現(xiàn)ICarryPassenger接口,飛機(jī)還可以實(shí)現(xiàn)IFlyable接口(雖然沒有用到。。):
1
2
3
4
5
6
7
8
9
10
11
12
|
public class Car implements ICarryPassenger { int passengerNum; //實(shí)現(xiàn)carry方法 @Override public void carry(Passenger passenger) { System.out.println( "Passenger:" +passenger.getName()+ " travel by Car." ); passengerNum++; System.out.println( "Car carries: " +passengerNum+ " passenger." ); } } |
1
2
3
4
5
6
7
8
9
10
11
|
public class Train implements ICarryPassenger { int passengerNum; @Override public void carry(Passenger passenger) { System.out.println( "Passenger:" +passenger.getName()+ " travel by Train." ); passengerNum++; System.out.println( "Train carries: " +passengerNum+ " passenger." ); } } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class Airplane implements IFlyable,ICarryPassenger{ private int passengerNum; //乘客數(shù)量 //實(shí)現(xiàn)Fly方法 @Override public void fly() { System.out.println( "Airplane is flying." ); } //實(shí)現(xiàn)carry方法 @Override public void carry(Passenger passenger) { System.out.println( "Passenger:" +passenger.getName()+ " travel by Airplane." ); passengerNum++; System.out.println( "Airplane carries: " +passengerNum+ " passengers." ); } } |
好的,現(xiàn)在我們寫一個(gè)測(cè)試類來進(jìn)行測(cè)試:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class Test { public static void main(String[] args) { //有6個(gè)乘客想要去旅游,對(duì)于旅行方式?jīng)]有側(cè)重,隨機(jī)分配交通工具 Random random = new Random(); Passenger[] passengers = new Passenger[ 6 ]; //聲明6個(gè)乘客 for ( int i= 0 ;i< 6 ;i++){ passengers[i] = new Passenger( "Passenger[" +i+ "]" ); } ICarryPassenger[] icp = new ICarryPassenger[ 3 ]; //聲明3種交通方式 icp[ 0 ] = new Airplane(); icp[ 1 ] = new Car(); icp[ 2 ] = new Train(); for ( int i= 0 ;i< 6 ;i++){ passengers[i].travelBy(icp[random.nextInt( 3 )]); } } } |
輸出如下:
Passenger:Passenger[0] travel by Airplane.
Airplane carries: 1 passengers.
Passenger:Passenger[1] travel by Train.
Train carries: 1 passenger.
Passenger:Passenger[2] travel by Airplane.
Airplane carries: 2 passengers.
Passenger:Passenger[3] travel by Car.
Car carries: 1 passenger.
Passenger:Passenger[4] travel by Train.
Train carries: 2 passenger.
Passenger:Passenger[5] travel by Airplane.
Airplane carries: 3 passengers.
因?yàn)轱w機(jī)跟火車,汽車之間并沒有太大關(guān)聯(lián),顯然無法直接抽象出父類,它們僅有相同的行為,那就是載客,所以使用接口是最合適的。
至此,本篇講解完畢,想必通過這一篇的講解,對(duì)于抽象類和接口的區(qū)別應(yīng)該有了更好的理解吧,如果有更好的栗子,歡迎大家留言交流,也歡迎大家繼續(xù)關(guān)注。
以上就是Java 抽象類與接口的對(duì)比的詳細(xì)內(nèi)容,更多關(guān)于Java 抽象類與接口的資料請(qǐng)關(guān)注服務(wù)器之家其它相關(guān)文章!
原文鏈接:https://cloud.tencent.com/developer/article/1016598