最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

謹(jǐn)慎使用Java8的默認(rèn)方法

 更新時(shí)間:2016年01月23日 10:13:34   投稿:lijiao  
為什么要謹(jǐn)慎使用Java8的默認(rèn)方法?本文給出了為什么要慎用Java8默認(rèn)方法的原因,解釋的很詳細(xì),感興趣的朋友可以參考一下

默認(rèn)方法給JVM的指令集增加了一個(gè)非常不錯(cuò)的新特性。使用了默認(rèn)方法之后,如果庫(kù)中的接口增加了新的方法,實(shí)現(xiàn)了這個(gè)接口的用戶類(lèi)能夠自動(dòng)獲得這個(gè)方法的默認(rèn)實(shí)現(xiàn)。一旦用戶想更新他的實(shí)現(xiàn)類(lèi)的話,只需覆蓋一下這個(gè)默認(rèn)方法就可以了,取而代之的是一個(gè)在特定場(chǎng)景下更有意義的實(shí)現(xiàn)。更棒的是,用戶可以在重寫(xiě)的方法里面調(diào)用接口的默認(rèn)實(shí)現(xiàn)來(lái)增加一些額外的功能。

目前為止一切都還不錯(cuò)。然而,給現(xiàn)有的Java接口增加默認(rèn)方法可能會(huì)導(dǎo)致代碼的不兼容??磦€(gè)例子就很容易能明白了。假設(shè)有一個(gè)庫(kù),它需要用戶實(shí)現(xiàn)它的一個(gè)接口作為輸入:

interface SimpleInput {
 void foo();
 void bar();
}
 
abstract class SimpleInputAdapter implements SimpleInput {
 @Override
 public void bar() {
 // some default behavior ...
 }
}
 

在Java 8以前,上述這種接口和一個(gè)對(duì)應(yīng)的適配器類(lèi)的組合在Java語(yǔ)言中是一種很常見(jiàn)的模式。類(lèi)庫(kù)的開(kāi)發(fā)人員提供了一個(gè)適配器來(lái)減少庫(kù)使用者的編碼量。然而提供這個(gè)接口的目的其實(shí)是為了能實(shí)現(xiàn)某種類(lèi)似多重繼承的關(guān)系。

我們假設(shè)有一個(gè)用戶使用了這個(gè)適配器:

class MyInput extends SimpleInputAdapter{
 @Override
 public void foo() {
 // do something ...
 }
 @Override
 public void bar() {
 super.bar();
 // do something additionally ...
 }
}
 

有了這個(gè)實(shí)現(xiàn),用戶可以和庫(kù)進(jìn)行交互了。注意這個(gè)實(shí)現(xiàn)是如何重寫(xiě)bar方法來(lái)給默認(rèn)的實(shí)現(xiàn)增加額外的功能的。

那如果這個(gè)庫(kù)遷移到Java 8的話會(huì)怎樣?首先,這個(gè)庫(kù)很可能會(huì)廢棄掉這個(gè)適配器類(lèi)并將這個(gè)功能遷移到默認(rèn)方法里。最終這個(gè)接口看起來(lái)會(huì)是這樣的:

interface SimpleInput {
 void foo();
 default void bar() {
 // some default behavior
 }
}}
 

有了這個(gè)新接口后,用戶得更新他的代碼來(lái)使用這個(gè)默認(rèn)方法,而不再是適配器類(lèi)了。使用新接口而非適配器類(lèi)的一大好處就是,用戶可以去繼承一個(gè)別的類(lèi)而不是這個(gè)適配器類(lèi)了。我們來(lái)動(dòng)手實(shí)踐一下,將MyInput類(lèi)改造成使用默認(rèn)方法。由于現(xiàn)在我們可以繼承別的類(lèi)了,我們?cè)兕~外地?cái)U(kuò)展一個(gè)第三方的基類(lèi)試試。這個(gè)基類(lèi)具體是做什么的在這里并不重要,我們先假設(shè)一下這么做對(duì)我們這個(gè)用例來(lái)說(shuō)是有意義的。

class MyInput extends ThirdPartyBaseClass implements SimpleInput {
 @Override
 public void foo() {
 // do something ...
 }
 @Override
 public void bar() {
 SimpleInput.super.foo();
 // do something additionally ... 
 }
}
 

為了實(shí)現(xiàn)和原先那個(gè)類(lèi)同樣的功能,這里我們用到了Java 8的新語(yǔ)法來(lái)調(diào)用接口的默認(rèn)方法。同樣的,我們把myMethod的邏輯放到某個(gè)基類(lèi)MyBase里面??梢源反芳绨蚍潘上铝?。重構(gòu)之后棒極了!

我們使用的這個(gè)庫(kù)得到了很大的改進(jìn)。然而,維護(hù)人員需要添加另一個(gè)接口來(lái)實(shí)現(xiàn)一些額外的功能。這個(gè)接口叫做CompexInput ,它繼承了SimpleInput類(lèi),并增加了一個(gè)額外的方法。由于通常都認(rèn)為默認(rèn)方法是可以放心地添加的,因此維護(hù)人員重寫(xiě)了SimpleInput類(lèi)的默認(rèn)方法并添加了一些額外的動(dòng)作來(lái)給用戶提供一個(gè)更好的默認(rèn)實(shí)現(xiàn)。畢竟使用適配器類(lèi)的時(shí)候這個(gè)做法也十分常見(jiàn):

interface ComplexInput extends SimpleInput {
 void qux();
 @Override
 default void bar() {
 SimpleInput.super.bar(); 
 // so complex, we need to do more ...
 }
} 
 

這個(gè)新特性看起來(lái)非常不錯(cuò),因此ThirdPartyBaseClass類(lèi)的維護(hù)人員也決定使用這個(gè)庫(kù)了。為了實(shí)現(xiàn)這個(gè),他將ThirdPartyBaseClass類(lèi)實(shí)現(xiàn)了ComplexInput接口。

但這樣的話對(duì)MyInput類(lèi)意味著什么?由于它繼承了ThirdPartyBaseClass類(lèi),因此默認(rèn)實(shí)現(xiàn)了ComplexInput接口,這樣的話調(diào)用SimpleInput的默認(rèn)方法就不合法了。結(jié)果就是,用戶的代碼最后無(wú)法通過(guò)編譯。還有就是,現(xiàn)在已經(jīng)徹底無(wú)法調(diào)用這個(gè)方法了,因?yàn)镴ava把這種調(diào)用間接父類(lèi)的super-super方法認(rèn)為是不合法的。你只能去調(diào)用ComplexInput接口的默認(rèn)方法了。然而這首先需要你在MyInput類(lèi)中顯式的實(shí)現(xiàn)一下這個(gè)接口。對(duì)于這個(gè)庫(kù)的用戶而言,這些改動(dòng)完全是意想不到的。

(注:簡(jiǎn)單點(diǎn)說(shuō)其實(shí)就是:

interface A {
 default void test() {
  
 }
}

interface B extends A {
 default void test() {
  
 }
}

public class Test implements B {
 public void test() {
  B.super.test();
  //A.super.test(); 錯(cuò)誤
 }


}

當(dāng)然這么寫(xiě)的話是用戶主動(dòng)選擇實(shí)現(xiàn)了B接口,而文中的例子由于引入了一個(gè)基類(lèi),因此由于庫(kù)和基類(lèi)中都進(jìn)行了一個(gè)看似沒(méi)有影響的改動(dòng),實(shí)際上卻導(dǎo)致用戶代碼無(wú)法通過(guò)編譯)

很奇怪的是,Java在運(yùn)行時(shí)并沒(méi)有對(duì)這個(gè)進(jìn)行區(qū)分。JVM的校驗(yàn)器允許一個(gè)編譯過(guò)的類(lèi)進(jìn)行SimpleInput::foo方法的調(diào)用,盡管加載的這個(gè)類(lèi)繼承了ThirdPartyBaseClass的更新版本后隱式地實(shí)現(xiàn)了ComplexInput接口。要怪只能怪編譯器了。(注:編譯器與運(yùn)行時(shí)的行為不一致)

那我們從中學(xué)到了什么?簡(jiǎn)單地說(shuō),不要在另一個(gè)接口中重寫(xiě)原接口的默認(rèn)方法。不要用另一個(gè)默認(rèn)方法來(lái)重寫(xiě)它,也不要某個(gè)抽象方法來(lái)重寫(xiě)它??偠灾褂媚J(rèn)方法時(shí)應(yīng)當(dāng)十分謹(jǐn)慎。雖然它們使得Java現(xiàn)有的集合庫(kù)的接口更容易改進(jìn)了,但它允許你在類(lèi)的繼承結(jié)構(gòu)中進(jìn)行方法調(diào)用,這本質(zhì)上其實(shí)是增加了復(fù)雜性。在Java 7以前,你只需遍歷線性的類(lèi)層次結(jié)構(gòu)看一下實(shí)際調(diào)用的代碼就可以了。當(dāng)你覺(jué)得的確需要的時(shí)候,再去使用默認(rèn)方法。

以上就是針對(duì)為什么要慎用Java8的默認(rèn)方法進(jìn)行的詳細(xì)解釋?zhuān)M麑?duì)大家的學(xué)習(xí)有所幫助。

相關(guān)文章

  • Java單鏈表的簡(jiǎn)單操作實(shí)現(xiàn)教程

    Java單鏈表的簡(jiǎn)單操作實(shí)現(xiàn)教程

    這篇文章主要給大家介紹了關(guān)于Java單鏈表的簡(jiǎn)單操作實(shí)現(xiàn)教程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • 淺談一下Java的雙親委派模式

    淺談一下Java的雙親委派模式

    這篇文章主要介紹了一下Java的雙親委派模式,雙親委派指得是,JVM在加載類(lèi)時(shí),會(huì)委派給ExtClassLoader和BootstrapClassLoader進(jìn)?加載,如果沒(méi)加載到才由??進(jìn)?加載,需要的朋友可以參考下
    2023-04-04
  • Java中java.lang.ClassCastException異常原因及解決方法

    Java中java.lang.ClassCastException異常原因及解決方法

    大家好,本篇文章主要講的是Java中java.lang.ClassCastException異常原因及解決方法,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-01-01
  • spring cloud gateway轉(zhuǎn)發(fā)服務(wù)報(bào)錯(cuò)的解決

    spring cloud gateway轉(zhuǎn)發(fā)服務(wù)報(bào)錯(cuò)的解決

    這篇文章主要介紹了spring cloud gateway轉(zhuǎn)發(fā)服務(wù)報(bào)錯(cuò)的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java基于Scanner對(duì)象的簡(jiǎn)單輸入計(jì)算功能示例

    Java基于Scanner對(duì)象的簡(jiǎn)單輸入計(jì)算功能示例

    這篇文章主要介紹了Java基于Scanner對(duì)象的簡(jiǎn)單輸入計(jì)算功能,結(jié)合實(shí)例形式分析了Java使用Scanner對(duì)象獲取用戶輸入半徑值計(jì)算圓形面積功能,需要的朋友可以參考下
    2018-01-01
  • 關(guān)于使用MyBatis簡(jiǎn)化JDBC開(kāi)發(fā)和解決SQL語(yǔ)句警告的問(wèn)題

    關(guān)于使用MyBatis簡(jiǎn)化JDBC開(kāi)發(fā)和解決SQL語(yǔ)句警告的問(wèn)題

    這篇文章主要介紹了關(guān)于使用MyBatis簡(jiǎn)化JDBC開(kāi)發(fā)和解決SQL語(yǔ)句警告的問(wèn)題,如果idea和數(shù)據(jù)庫(kù)沒(méi)有建立鏈接,idea不識(shí)別表的信息,就會(huì)出現(xiàn)SQL語(yǔ)句的警告,需要的朋友可以參考下
    2023-05-05
  • Java用鄰接矩陣存儲(chǔ)圖的示例代碼

    Java用鄰接矩陣存儲(chǔ)圖的示例代碼

    鄰接矩陣通常采用一個(gè)一維數(shù)組存儲(chǔ)圖中節(jié)點(diǎn)的信息,采用一個(gè)二維數(shù)組存儲(chǔ)圖中節(jié)點(diǎn)之間的鄰接關(guān)系。本文將利用Java實(shí)現(xiàn)用鄰接矩陣存儲(chǔ)圖,需要的可以參考一下
    2022-06-06
  • Spring Boot線程池使用的一些實(shí)用心得

    Spring Boot線程池使用的一些實(shí)用心得

    理論上線程越多程序可能更快,但在實(shí)際使用中我們需要考慮到線程本身的創(chuàng)建以及銷(xiāo)毀的資源消耗,以及保護(hù)操作系統(tǒng)本身的目的我們通常需要將線程限制在一定的范圍之類(lèi),這篇文章主要給大家介紹了關(guān)于Spring Boot線程池使用的一些實(shí)用心得,需要的朋友可以參考下
    2021-09-09
  • PowerDesigner連接數(shù)據(jù)庫(kù)的實(shí)例詳解

    PowerDesigner連接數(shù)據(jù)庫(kù)的實(shí)例詳解

    這篇文章主要介紹了PowerDesigner連接數(shù)據(jù)庫(kù)的實(shí)例詳解的相關(guān)資料,如有疑問(wèn)請(qǐng)留言或者到本站社區(qū)交流討論,需要的朋友可以參考下
    2017-10-10
  • Java內(nèi)存模型中的虛擬機(jī)棧原理分析

    Java內(nèi)存模型中的虛擬機(jī)棧原理分析

    這篇文章主要介紹了Java內(nèi)存模型中的虛擬機(jī)棧原理分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11

最新評(píng)論

涟源市| 麻阳| 阜新市| 彩票| 宾阳县| 康马县| 苍南县| 天津市| 和龙市| 延津县| 谷城县| 平舆县| 平邑县| 安福县| 宝应县| 桦甸市| 辽宁省| 时尚| 庆阳市| 镇巴县| 日喀则市| 白朗县| 武宁县| 抚顺市| 开阳县| 安丘市| 徐汇区| 阿勒泰市| 普定县| 长武县| 丰顺县| 化德县| 麻栗坡县| 上杭县| 敦煌市| 巴彦淖尔市| 娄烦县| 长寿区| 化德县| 铁力市| 丰都县|