Java8中的默認(rèn)方法(面試者必看)
背景
在Java8之前,定義在接口中的所有方法都需要在接口實現(xiàn)類中提供一個實現(xiàn),如果接口的提供者需要升級接口,添加新的方法,那么所有的實現(xiàn)類都需要把這個新增的方法實現(xiàn)一遍,如果說所有的實現(xiàn)類能夠自己控制的話,那么還能接受,但是現(xiàn)實情況是實現(xiàn)類可能不受自己控制。比如說Java中的集合框架中的List接口添加一個方法,那么Apache Commons這種框架就會很難受,必須修改所有實現(xiàn)了List的實現(xiàn)類
現(xiàn)在的接口有哪些不便
向已經(jīng)發(fā)布的接口中添加新的方法是問題的根源,一旦接口發(fā)生變化,接口的實現(xiàn)者都需要更新代碼,實現(xiàn)新增的接口
接口中有些方法是可選的,不是所有的實現(xiàn)者都需要實現(xiàn),這個時候?qū)崿F(xiàn)類不得不實現(xiàn)一個空的方法,或者是提供一個Adapter對接口中所有的方法做空實現(xiàn),在Spring中我們可看到很多這種例子,比如WebMvcConfigurerAdapter
@Deprecated public abstract class WebMvcConfigurerAdapter implements WebMvcConfigurer { @Override public void configurePathMatch(PathMatchConfigurer configurer) { } @Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { } @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { } 省略其他代碼... }
在Java8以后這些類都被標(biāo)注成了過期@Deprecated
默認(rèn)方法的簡介
為了解決上述問題,在Java8中允許指定接口做默認(rèn)實現(xiàn),未指定的接口由實現(xiàn)類去實現(xiàn)。如何標(biāo)識出接口是默認(rèn)實現(xiàn)呢?方法前面加上default關(guān)鍵字。比如Spring中的WebMvcConfigurer
public interface WebMvcConfigurer { default void configurePathMatch(PathMatchConfigurer configurer) { } default void configureContentNegotiation(ContentNegotiationConfigurer configurer) { } default void configureAsyncSupport(AsyncSupportConfigurer configurer) { } 省略其他代碼... }
從現(xiàn)在看來,可能大家都會有個疑問,默認(rèn)方法和抽象類有什么區(qū)別呢?
- 默認(rèn)方法不能有實例變量,抽象類可以有
- 一個類只能繼承一個抽象類,當(dāng)時可以實現(xiàn)多個接口
默認(rèn)方法的使用場景
可選方法
為接口提供可選的方法,給出默認(rèn)實現(xiàn),這樣實現(xiàn)類就不用顯示的去提供一個空的方法;這種場景剛才我們在上面已經(jīng)說到了,spring中有大量的例子
實現(xiàn)多繼承
繼承是面向?qū)ο蟮奶匦灾?,在Java中一直以來都是單繼承的原則,Java8中默認(rèn)方法為實現(xiàn)多繼承提供了可能(由于接口中不能有實例對象,所以能夠抽象的到接口中的行為一般都是比較小的模塊);從個人的經(jīng)歷來看,做游戲是訓(xùn)練自己面向?qū)ο笏季S的最好方式(以后有機會分享一下小游戲的制作),因為現(xiàn)在大部分學(xué)Java的同學(xué)學(xué)完Java基礎(chǔ)后就直接進入JavaWeb的學(xué)習(xí),整合各種框架,只能在通用的三層架構(gòu)(Controller、Service、Dao)中寫自己的邏輯。
相信很多人在都做個坦克大戰(zhàn)的游戲,如果用Java8中的默認(rèn)方法如何設(shè)計好多繼承呢?
這里我們舉個簡單的例子,定義了三個接口:
- Moveable:允許移動的物體,把移動的邏輯放入到這個接口中的默認(rèn)方法
- Attackable: 允許攻擊的物體,把攻擊的通用邏輯放入到默認(rèn)方法,不通用的邏輯通過模板方法給實現(xiàn)類處理
- Location: 獲取物體的坐標(biāo)
通過這些接口的組合方式,我們就可以為游戲創(chuàng)建不同的實現(xiàn)類,比如說坦克、草地、墻壁...
解決默認(rèn)方法沖突規(guī)則(面試者必看)
通過上面的例子,我們體驗的默認(rèn)方法給我們帶來了多繼承的便利,但是讓我們思考下,如果出現(xiàn)了不同的類出現(xiàn)的相同簽名的默認(rèn)方法,實際在運行的時候應(yīng)該如何選擇呢?客官不慌,有辦法的
- 類中的方法優(yōu)先級最高。如果類或者父類(抽象類也OK)中聲明了相同簽名的方法,那么優(yōu)先級最高
- 如果第一條無法確定,那么最具體的的實現(xiàn)的默認(rèn)方法;很繞,舉例子:B接口繼承了A,B就更加具體,那么B中的方法優(yōu)先級最高
- 如果上面兩個都無法判斷,那么編譯會報錯,需要在實現(xiàn)接口,然后手動顯式調(diào)用
public class C implements A, B { void pint() { B.supper.print(); // 顯式調(diào)用 } }
菱形繼承問題
為了說明上面的三個原則,我們直接來看看最復(fù)雜的菱形繼承問題
public interface A { default void print(){ System.out.println("Class A"); } } public interface B extend A {} public interface C extend A {} public class D implement B, C { public static void main(String[] args) { new D().print() } }
這種情況下B,C都沒有自己的實現(xiàn),實際上就只有A有實現(xiàn),那么會打印Class A
如果說這個時候把接口B接口改一下
public interface B extends A { default void print(){ System.out.println("Class B"); } }
根據(jù)原則(2),B繼承于A,更加具體,所以打印結(jié)果應(yīng)該是B
如果說把接口C修改一下
public interface C extends A { default void print(){ System.out.println("Class C"); } }
這時候我們發(fā)現(xiàn)編譯報錯,需要我們自己手動指定,修改D中的代碼
public class D implements B, C { @Override public void print() { C.super.print(); } public static void main(String[] args) { new D().print(); } }
總結(jié)
- Java8中的默認(rèn)方法需要使用default來修飾
- 默認(rèn)方法的使用場景可選方法和多繼承
- 三個原則解決相同簽名的默認(rèn)方法沖突問題
到此這篇關(guān)于Java8中的默認(rèn)方法(面試者必看)的文章就介紹到這了,更多相關(guān)Java8 默認(rèn)方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在ssm中使用ModelAndView跳轉(zhuǎn)頁面失效的解決
這篇文章主要介紹了在ssm中使用ModelAndView跳轉(zhuǎn)頁面失效的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05SpringBoot+Redis防止惡意刷新與暴力請求接口的實現(xiàn)
這篇文章主要為大家介紹了如何利用springboot和Redis來實現(xiàn)防止惡意刷新與暴力請求接口,文中的示例代碼講解詳細(xì),需要的可以參考一下2022-06-06使用logback實現(xiàn)按自己的需求打印日志到自定義的文件里
這篇文章主要介紹了使用logback實現(xiàn)按自己的需求打印日志到自定義的文件里,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08使用maven創(chuàng)建web項目的方法步驟(圖文)
本篇文章主要介紹了使用maven創(chuàng)建web項目的方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-01-01XML Web 服務(wù) Eclipse實現(xiàn)sun-jaxws.xml文件的方法
在sun-jaxws.xml文件,可以配置endpoint、handler-chain等內(nèi)容,在這個文件中配置的內(nèi)容會覆蓋在Java代碼中使用注解屬性配置的的內(nèi)容,本文給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2023-11-11