<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java 8 有多牛逼?打破一切你對(duì)接口的認(rèn)知!

          共 1375字,需瀏覽 3分鐘

           ·

          2020-10-16 14:48

          Java技術(shù)棧

          www.javastack.cn

          關(guān)注閱讀更多優(yōu)質(zhì)文章



          前段時(shí)間面試了一個(gè) 39 歲的程序員,結(jié)果不是很理想,沒(méi)看過(guò)的點(diǎn)擊這里閱讀。

          最近也面試一些 Java 程序員,不乏工作 4、5 年經(jīng)驗(yàn)的,當(dāng)我問(wèn)他一些 Java 8 的新特性時(shí),大多卻答不上來(lái)。

          比如下面這道題:

          棧長(zhǎng):接口里面可以寫方法嗎?

          小A:當(dāng)然可以啊,默認(rèn)就是抽象方法。

          棧長(zhǎng):那接口里面可以寫實(shí)現(xiàn)方法嗎?

          小A:不可以,所有方法必須是抽象的。

          棧長(zhǎng):你確定嗎?

          小A:確定……

          小A看起來(lái)對(duì)我的問(wèn)題有點(diǎn)懷疑人生,心里肯定估摸著,我不會(huì)在給他埋了什么坑吧。然后他還是仔細(xì)再想了一下,最后還是斬釘截鐵的告訴我:接口里面只能寫抽象方法,不能寫實(shí)現(xiàn)方法。

          棧長(zhǎng):接口里面是可以寫實(shí)現(xiàn)方法的,Java 8 開(kāi)始就可以了,你用過(guò) Java 8 嗎?

          小A:好吧,看來(lái)是我學(xué)藝不精,Java 8 有了解一點(diǎn),比如那個(gè) Lambda 表達(dá)式,但實(shí)際項(xiàng)目中也沒(méi)怎么用。

          通過(guò)和小A的交流,我也看到了許多開(kāi)發(fā)者的問(wèn)題,雖然開(kāi)發(fā)版本用的是 Java 8,但實(shí)際用的還是 Java 8 之前的最基礎(chǔ)的語(yǔ)法,對(duì) Java 8 新增的特性一無(wú)所知。

          Java 8 至 2014 年發(fā)布至今,已經(jīng)過(guò)了 6 個(gè)年頭了,最新的 Java 14 都發(fā)布了,OK,這個(gè)不在本篇討論范圍之內(nèi), Java ?8+ 系列教程請(qǐng)關(guān)注公眾號(hào)Java技術(shù)?;貜?fù) "java" 進(jìn)行閱讀,本篇就是想順著問(wèn)小A的這個(gè)問(wèn)題展開(kāi)。

          什么是默認(rèn)方法和靜態(tài)方法?

          上面也說(shuō)了,Java 8 開(kāi)始是可以有方法實(shí)現(xiàn)的,可以在接口中添加默認(rèn)方法和靜態(tài)方法。

          默認(rèn)方法用 default 修飾,只能用在接口中,靜態(tài)方法用 static 修飾,這個(gè)我們不陌生了。并且接口中的默認(rèn)方法、靜態(tài)方法可以同時(shí)有多個(gè)。

          在接口中寫實(shí)現(xiàn)方法一點(diǎn)也不稀奇,像這樣的用法,從 Java 8 到 Java 14 已是遍地開(kāi)花,到處都可以看到接口默認(rèn)方法和靜態(tài)方法的身影。

          比如我們來(lái)看下在 JDK API 中 java.util.Map 關(guān)于接口默認(rèn)方法和靜態(tài)方法的應(yīng)用。

          /*
          *?來(lái)源公眾號(hào):Java技術(shù)棧?
          */
          public?interface?Map?{

          ????...
          ????
          ????/**
          ????*?接口默認(rèn)方法
          ????*/
          ????default?boolean?remove(Object?key,?Object?value)?{
          ????????Object?curValue?=?get(key);
          ????????if?(!Objects.equals(curValue,?value)?||
          ????????????(curValue?==?null?&&?!containsKey(key)))?{
          ????????????return?false;
          ????????}
          ????????remove(key);
          ????????return?true;
          ????}
          ????
          ????...
          ????
          ????/**
          ????*?接口靜態(tài)方法
          ????*/
          ????public?static?,?V>?Comparator>?comparingByKey()?{
          ????????return?(Comparator>?&?Serializable)
          ????????????(c1,?c2)?->?c1.getKey().compareTo(c2.getKey());
          ????}
          ????
          ????...
          ????
          }????

          為什么要有接口默認(rèn)方法?

          舉一個(gè)很現(xiàn)實(shí)的例子:

          我們的接口老早就寫好了,后面因?yàn)楦鞣N業(yè)務(wù)問(wèn)題,避免不了要修改接口。

          在 Java 8 之前,比如要在一個(gè)接口中添加一個(gè)抽象方法,那所有的接口實(shí)現(xiàn)類都要去實(shí)現(xiàn)這個(gè)方法,不然就會(huì)編譯錯(cuò)誤,而某些實(shí)現(xiàn)類根本就不需要實(shí)現(xiàn)這個(gè)方法也被迫要寫一個(gè)空實(shí)現(xiàn),改動(dòng)會(huì)非常大。

          所以,接口默認(rèn)方法就是為了解決這個(gè)問(wèn)題,只要在一個(gè)接口添加了一個(gè)默認(rèn)方法,所有的實(shí)現(xiàn)類就自動(dòng)繼承,不需要改動(dòng)任何實(shí)現(xiàn)類,也不會(huì)影響業(yè)務(wù),爽歪歪。

          另外,接口默認(rèn)方法可以被接口實(shí)現(xiàn)類重寫。

          為什么要有接口靜態(tài)方法?

          接口靜態(tài)方法和默認(rèn)方法類似,只是接口靜態(tài)方法不可以被接口實(shí)現(xiàn)類重寫。

          接口靜態(tài)方法只可以直接通過(guò)靜態(tài)方法所在的 接口名.靜態(tài)方法名 來(lái)調(diào)用。

          接口默認(rèn)方法多繼承沖突問(wèn)題

          因?yàn)榻涌谀J(rèn)方法可以被繼承并重寫,如果繼承的多個(gè)接口都存在相同的默認(rèn)方法,那就存在沖突問(wèn)題。

          下面我會(huì)列舉 3 個(gè)沖突示例場(chǎng)景。

          沖突一

          來(lái)看下面這段程序:

          /*
          *?來(lái)源公眾號(hào):Java技術(shù)棧?
          */
          interface?People?{
          ?default?void?eat(){
          ??System.out.println("人吃飯");
          ?}
          }

          /*
          *?來(lái)源公眾號(hào):Java技術(shù)棧?
          */
          interface?Man?{
          ?default?void?eat(){
          ??System.out.println("男人吃飯");
          ?}
          }

          /*
          *?來(lái)源公眾號(hào):Java技術(shù)棧?
          */
          interface?Boy?extends?Man,?People?{

          }

          Boy 同時(shí)繼承了 People 和 Man,此時(shí)在 IDEA 編輯器中就會(huì)報(bào)錯(cuò):

          這就是接口多繼承帶來(lái)的沖突問(wèn)題,Boy 不知道該繼承誰(shuí)的,這顯然也是個(gè)問(wèn)題,IDEA 也會(huì)提示,需要重寫這個(gè)方法才能解決問(wèn)題:

          /*
          *?來(lái)源公眾號(hào):Java技術(shù)棧?
          */
          interface?Boy?extends?Man,?People?{

          ?@Override
          ?default?void?eat()?{
          ??System.out.println("男孩吃飯");
          ?}
          }

          在方法里面還能直接調(diào)用指定父接口的默認(rèn)方法,比如:

          /*
          *?來(lái)源公眾號(hào):Java技術(shù)棧?
          */
          interface?Boy?extends?Man,?People?{

          ?@Override
          ?default?void?eat()?{
          ??People.super.eat();
          ??Man.super.eat();
          ??System.out.println("男孩吃飯");
          ?}
          }

          再加個(gè)實(shí)現(xiàn)類測(cè)試一下:

          /*
          *?來(lái)源公眾號(hào):Java技術(shù)棧?
          */
          static?class?Student?implements?Boy?{

          ?public?static?void?main(String[]?args)?{
          ??Student?student?=?new?Student();
          ??student.eat();
          ?}

          }

          輸出:

          人吃飯
          男人吃飯
          男孩吃飯

          嗯,很強(qiáng)大!

          沖突二

          我們?cè)贀Q一種寫法,把 Man 繼承 People,然后 Man 重寫 People 中的默認(rèn)方法。

          此時(shí),編輯器不報(bào)錯(cuò)了,而 People 的默認(rèn)方法置灰了,提示沒(méi)有被用到。

          再運(yùn)行一下上面的示例,輸出:

          男人吃飯

          因?yàn)?Man 繼承 People,Man 又重定了默認(rèn)方法。很顯然,這個(gè)時(shí)候,Boy 知道該繼承誰(shuí)的默認(rèn)方法了。

          沖突三

          在 Man 接口中新增一個(gè)方法:say,然后在 Boy 接口中新增一個(gè)默認(rèn)方法:say。

          這時(shí)候,Man 中的抽象方法居然被忽略了,IDEA 都提示說(shuō)沒(méi)用到,這顯然是默認(rèn)方法優(yōu)先于抽象方法。

          總結(jié)

          本文介紹了 Java 8 的默認(rèn)方法和靜態(tài)方法,以及默認(rèn)方法的沖突問(wèn)題解決方案。所以,大家出去面試時(shí),再也不要說(shuō)接口不能寫實(shí)現(xiàn)方法了,那就太 OUT 了。。

          文中只舉了 3 個(gè)默認(rèn)方法的沖突場(chǎng)景,不確定還沒(méi)有更多沖突問(wèn)題。默認(rèn)方法雖然解決了接口變動(dòng)帶來(lái)的問(wèn)題,但如果設(shè)計(jì)不當(dāng),或者過(guò)度設(shè)計(jì),其帶來(lái)的方法沖突問(wèn)題也是需要引起注意的。

          本文到此就結(jié)束了,之前我也陸續(xù)分享了一系列 Java 8+ 新特性文章,感興趣的可以關(guān)注公眾號(hào)Java技術(shù)棧在菜單中獲取,后續(xù)還會(huì)繼續(xù)分享,公眾號(hào)第一時(shí)間推送,持續(xù)關(guān)注哦。

          老鐵們,覺(jué)得有用,在看、轉(zhuǎn)發(fā)分享一下哦~





          關(guān)注Java技術(shù)??锤喔韶?/strong>



          戳原文,獲取精選面試題!
          瀏覽 35
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美性猛交XXXX免费看久久久 | 最黄视频伦乱日本 | 日韩在线观看中文字幕 | 特色黄色片| 亚洲色拍视频 |