国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Java > 正文

謹慎使用Java8的默認方法

2019-11-26 14:39:34
字體:
來源:轉載
供稿:網(wǎng)友

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

目前為止一切都還不錯。然而,給現(xiàn)有的Java接口增加默認方法可能會導致代碼的不兼容。看個例子就很容易能明白了。假設有一個庫,它需要用戶實現(xiàn)它的一個接口作為輸入:

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

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

我們假設有一個用戶使用了這個適配器:

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

有了這個實現(xiàn),用戶可以和庫進行交互了。注意這個實現(xiàn)是如何重寫bar方法來給默認的實現(xiàn)增加額外的功能的。

那如果這個庫遷移到Java 8的話會怎樣?首先,這個庫很可能會廢棄掉這個適配器類并將這個功能遷移到默認方法里。最終這個接口看起來會是這樣的:

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

有了這個新接口后,用戶得更新他的代碼來使用這個默認方法,而不再是適配器類了。使用新接口而非適配器類的一大好處就是,用戶可以去繼承一個別的類而不是這個適配器類了。我們來動手實踐一下,將MyInput類改造成使用默認方法。由于現(xiàn)在我們可以繼承別的類了,我們再額外地擴展一個第三方的基類試試。這個基類具體是做什么的在這里并不重要,我們先假設一下這么做對我們這個用例來說是有意義的。

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

為了實現(xiàn)和原先那個類同樣的功能,這里我們用到了Java 8的新語法來調(diào)用接口的默認方法。同樣的,我們把myMethod的邏輯放到某個基類MyBase里面。可以捶捶肩膀放松下了。重構之后棒極了!

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

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

這個新特性看起來非常不錯,因此ThirdPartyBaseClass類的維護人員也決定使用這個庫了。為了實現(xiàn)這個,他將ThirdPartyBaseClass類實現(xiàn)了ComplexInput接口。

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

(注:簡單點說其實就是:

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(); 錯誤 }}

當然這么寫的話是用戶主動選擇實現(xiàn)了B接口,而文中的例子由于引入了一個基類,因此由于庫和基類中都進行了一個看似沒有影響的改動,實際上卻導致用戶代碼無法通過編譯)

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

那我們從中學到了什么?簡單地說,不要在另一個接口中重寫原接口的默認方法。不要用另一個默認方法來重寫它,也不要某個抽象方法來重寫它。總而言之,使用默認方法時應當十分謹慎。雖然它們使得Java現(xiàn)有的集合庫的接口更容易改進了,但它允許你在類的繼承結構中進行方法調(diào)用,這本質(zhì)上其實是增加了復雜性。在Java 7以前,你只需遍歷線性的類層次結構看一下實際調(diào)用的代碼就可以了。當你覺得的確需要的時候,再去使用默認方法。

以上就是針對為什么要慎用Java8的默認方法進行的詳細解釋,希望對大家的學習有所幫助。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 攀枝花市| 罗山县| 桦川县| 大港区| 沁水县| 聂拉木县| 当涂县| 稷山县| 韶山市| 无极县| 泗阳县| 确山县| 沙雅县| 建湖县| 抚松县| 广昌县| 屏南县| 桐庐县| 米易县| 安福县| 徐水县| 桦川县| 莲花县| 昭觉县| 常山县| 福清市| 兴安盟| 五大连池市| 武胜县| 临猗县| 顺义区| 林西县| 天祝| 大方县| 贵定县| 盐山县| 临颍县| 普兰店市| 同德县| 万荣县| 循化|