對于面向目標編程來說,籠統(tǒng)是一個極具魅力的特征。假設(shè)一個程序員的籠統(tǒng)思維很差,那他在編程中就會遇到許多困難,無法把業(yè)務(wù)變成具體的代碼。在Java中,能夠經(jīng)過兩種方式來達到籠統(tǒng)的意圖,一種是籠統(tǒng)類,別的一種便是接口。
假設(shè)你現(xiàn)在就想知道籠統(tǒng)類與接口之間的差異,我能夠提前給你說一個:
一個類只能承繼一個籠統(tǒng)類,但卻能夠完成多個接口。
當然了,在沒有搞清楚接口究竟是什么,它能夠做什么之前,這個差異了解起來會有點難度。
01、接口是什么
接口是經(jīng)過interface關(guān)鍵字界說的,它能夠包括一些常量和辦法,來看下面這個示例。
publicinterfaceElectronic{
//常量
StringLED=”LED”;
//籠統(tǒng)辦法
intgetElectricityUse();
//靜態(tài)辦法
staticbooleanisEnergyEfficient(StringelecttronicType){
returnelecttronicType.equals(LED);
}
//默許辦法
defaultvoidprintDescription(){
System.out.println(“電子”);
}
}
1)接口中界說的變量會在編譯的時分主動加上publicstaticfinal潤飾符,也便是說LED變量其實是一個常量。
Java官方文檔上有這樣的聲明:
Everyfielddeclarationinthebodyofaninterfaceisimplicitlypublic,static,andfinal.
換句話說,接口能夠用來作為常量類運用,還能省掉掉publicstaticfinal,看似不錯的一種挑選,對吧?
不過,這種挑選并不可取。由于接口的原意是對辦法進行籠統(tǒng),而常量接口會對子類中的變量造成命名空間上的“污染”。
2)沒有運用private、default或許static關(guān)鍵字潤飾的辦法是隱式籠統(tǒng)的,在編譯的時分會主動加上publicabstract潤飾符。也便是說getElectricityUse()其實是一個籠統(tǒng)辦法,沒有辦法體——這是界說接口的原意。
3)從Java8開端,接口中答應(yīng)有靜態(tài)辦法,比如說isEnergyEfficient()辦法。
靜態(tài)辦法無法由(完成了該接口的)類的目標調(diào)用,它只能經(jīng)過接口的姓名來調(diào)用,比如說Electronic.isEnergyEfficient(“LED”)。
接口中界說靜態(tài)辦法的意圖是為了供給一種簡單的機制,使咱們不必創(chuàng)建目標就能調(diào)用辦法,然后提高接口的競爭力。
4)接口中答應(yīng)界說default辦法也是從Java8開端的,比如說printDescription(),它始終由一個代碼塊組成,為完成該接口而不掩蓋該辦法的類供給默許完成,也便是說,無法直接運用一個“;”號來結(jié)束默許辦法——編譯器會報錯的。
答應(yīng)在接口中界說默許辦法的理由是很充分的,由于一個接口可能有多個完成類,這些類就必須完成接口中界說的籠統(tǒng)類,不然編譯器就會報錯。假設(shè)咱們需求在一切的完成類中追加某個具體的辦法,在沒有default辦法的幫助下,咱們就必須挨個對完成類進行修改。
來看一下Electronic接口反編譯后的字節(jié)碼吧,你會發(fā)現(xiàn),接口中界說的一切變量或許辦法,都會主動添加上public關(guān)鍵字——假設(shè)你想知道編譯器在背面都靜靜做了哪些輔佐,記住反編譯字節(jié)碼就對了。
publicinterfaceElectronic
{
publicabstractintgetElectricityUse();
publicstaticbooleanisEnergyEfficient(StringelecttronicType)
{
returnelecttronicType.equals(“LED”);
}
publicvoidprintDescription()
{
System.out.println(“\u7535\u5B50″);
}
publicstaticfinalStringLED=”LED”;
}
有些讀者可能會問,“二哥,為什么我反編譯后的字節(jié)碼和你的不一樣,你用了什么反編譯東西?”其實沒有什么隱秘,微信搜「緘默沉靜王二」回復關(guān)鍵字「JAD」就能夠免費獲取了,超級好用。
02、界說接口的注意事項
由之前的比如咱們就能夠得出下面這些結(jié)論:
接口中答應(yīng)界說變量
接口中答應(yīng)界說籠統(tǒng)辦法
接口中答應(yīng)界說靜態(tài)辦法(Java8之后)
接口中答應(yīng)界說默許辦法(Java8之后)
除此之外,咱們還應(yīng)該知道:
1)接口不答應(yīng)直接實例化。
需求界說一個類去完成接口,然后再實例化。
publicclassComputerimplementsElectronic{
publicstaticvoidmain(String[]args){
newComputer();
}
@Override
publicintgetElectricityUse(){
return0;
}
}
2)接口能夠是空的,既不界說變量,也不界說辦法。
publicinterfaceSerializable{
}
Serializable是最典型的一個空的接口,我之前共享過一篇文章《JavaSerializable:分明就一個空的接口嘛》,感興趣的讀者能夠去我的個人博客看一看,你就了解了空接口的含義。
3)不要在界說接口的時分運用final關(guān)鍵字,不然會報編譯錯誤,由于接口便是為了讓子類完成的,而final阻止了這種行為。
4)接口的籠統(tǒng)辦法不能是private、protected或許final。
5)接口的變量是隱式publicstaticfinal,所以其值無法改變。
03、接口能夠做什么
1)使某些完成類具有咱們想要的功用,比如說,完成了Cloneable接口的類具有拷貝的功用,完成了Comparable或許Comparator的類具有比較功用。
Cloneable和Serializable一樣,都屬于符號型接口,它們內(nèi)部都是空的。完成了Cloneable接口的類能夠運用Object.clone()辦法,不然會拋出CloneNotSupportedException。
publicclassCloneableTestimplementsCloneable{
@Override
protectedObjectclone()throwsCloneNotSupportedException{
returnsuper.clone();
}
publicstaticvoidmain(String[]args)throwsCloneNotSupportedException{
CloneableTestc1=newCloneableTest();
CloneableTestc2=(CloneableTest)c1.clone();
}
}
運行后沒有報錯?,F(xiàn)在把implementsCloneable去掉。
publicclassCloneableTest{
@Override
protectedObjectclone()throwsCloneNotSupportedException{
returnsuper.clone();
}
publicstaticvoidmain(String[]args)throwsCloneNotSupportedException{
CloneableTestc1=newCloneableTest();
CloneableTestc2=(CloneableTest)c1.clone();
}
}
運行后拋出CloneNotSupportedException:
Exceptioninthread”main”java.lang.CloneNotSupportedException:com.cmower.baeldung.interface1.CloneableTest
atjava.base/java.lang.Object.clone(NativeMethod)
atcom.cmower.baeldung.interface1.CloneableTest.clone(CloneableTest.java:6)
atcom.cmower.baeldung.interface1.CloneableTest.main(CloneableTest.java:11)
至于Comparable和Comparator的用法,感興趣的讀者能夠參照我之前寫的別的一篇文章《來吧,一文完全搞懂Java中的Comparable和Comparator》。
http://www.itwanger.com/java/2020/01/04/java-comparable-comparator.html
2)Java原則上只支撐單一承繼,但經(jīng)過接口能夠完成多重承繼的意圖。
可能有些讀者會問,“二哥,為什么Java只支撐單一承繼?”簡單來解釋一下。
假設(shè)有兩個類一起承繼(extends)一個有特定辦法的父類,那么該辦法會被兩個子類重寫。然后,假設(shè)你決定一起承繼這兩個子類,那么在你調(diào)用該重寫辦法時,編譯器不能辨認你要調(diào)用哪個子類的辦法。這也正是著名的菱形問題,見下圖。
ClassC一起承繼了ClassA和ClassB,ClassC的目標在調(diào)用ClassA和ClassB中重載的辦法時,就不知道該調(diào)用ClassA的辦法,還是ClassB的辦法。
接口沒有這方面的困擾。來界說兩個接口,F(xiàn)ly會飛,Run會跑。
publicinterfaceFly{
voidfly();
}
publicinterfaceRun{
voidrun();
}
然后讓一個類一起完成這兩個接口。
publicclassPigimplementsFly,Run{
@Override
publicvoidfly(){
System.out.println(“會飛的豬”);
}
@Override
publicvoidrun(){
System.out.println(“會跑的豬”);
}
}
這就在某種方式上達到了多重承繼的意圖:實際世界里,豬的確只會跑,但在雷軍的眼里,站在風口的豬就會飛,這就需求賦予這只豬更多的能力,經(jīng)過籠統(tǒng)類是無法完成的,只能經(jīng)過接口。
3)完成多態(tài)。
什么是多態(tài)呢?通俗的了解,便是同一個事件發(fā)生在不同的目標上會發(fā)生不同的成果,鼠標左鍵點擊窗口上的X號能夠關(guān)閉窗口,點擊超鏈接卻能夠打開新的網(wǎng)頁。
多態(tài)能夠經(jīng)過承繼(extends)的聯(lián)系完成,也能夠經(jīng)過接口的方式完成。來看這樣一個比如。
Shape是表明一個形狀。
publicinterfaceShape{
Stringname();
}
圓是一個形狀。
publicclassCircleimplementsShape{
@Override
publicStringname(){
return”圓”;
}
}
正方形也是一個形狀。
publicclassSquareimplementsShape{
@Override
publicStringname(){
return”正方形”;
}
}
然后來看測驗類。
Listshapes=newArrayList<>();
ShapecircleShape=newCircle();
ShapesquareShape=newSquare();
shapes.add(circleShape);
shapes.add(squareShape);
for(Shapeshape:shapes){
System.out.println(shape.name());
}
多態(tài)的存在3個前提:
1、要有承繼聯(lián)系,Circle和Square都完成了Shape接口
2、子類要重寫父類的辦法,Circle和Square都重寫了name()辦法
3、父類引證指向子類目標,circleShape和squareShape的類型都為Shape,但前者指向的是Circle目標,后者指向的是Square目標。
然后,咱們來看一下測驗成果:
圓
正方形
也就意味著,雖然在for循環(huán)中,shape的類型都為Shape,但在調(diào)用name()辦法的時分,它知道Circle目標應(yīng)該調(diào)用Circle類的name()辦法,Square目標應(yīng)該調(diào)用Square類的name()辦法。
04、接口與籠統(tǒng)類的差異
好了,關(guān)于接口的一切,你應(yīng)該都搞清楚了?,F(xiàn)在回到讀者春夏秋冬的那條留言,“兄弟,說說籠統(tǒng)類和接口之間的差異?”
1)語法層面上
接口中不能有public和protected潤飾的辦法,籠統(tǒng)類中能夠有。
接口中的變量只能是隱式的常量,籠統(tǒng)類中能夠有恣意類型的變量。
一個類只能承繼一個籠統(tǒng)類,但卻能夠完成多個接口。
2)設(shè)計層面上
籠統(tǒng)類是對類的一種籠統(tǒng),承繼籠統(tǒng)類的類和籠統(tǒng)類本身是一種is-a的聯(lián)系。
接口是對類的某種行為的一種籠統(tǒng),接口和類之間并沒有很強的相關(guān)聯(lián)系,一切的類都能夠完成Serializable接口,然后具有序列化的功用。
就這么多吧,能說道這份上,我相信面試官就不會為難你了。
廣州天河區(qū)珠江新城富力盈力大廈北塔2706
020-38013166(網(wǎng)站咨詢專線)
400-001-5281 (售后服務(wù)熱線)
深圳市坂田十二橡樹莊園F1-7棟
Site/ http://www.szciya.com
E-mail/ itciya@vip.163.com
品牌服務(wù)專線:400-001-5281
長沙市天心區(qū)芙蓉中路三段398號新時空大廈5樓
聯(lián)系電話/ (+86 0731)88282200
品牌服務(wù)專線/ 400-966-8830
旗下運營網(wǎng)站:
Copyright ? 2016 廣州思洋文化傳播有限公司,保留所有權(quán)利。 粵ICP備09033321號