一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 謹慎使用Java8的默認方法

謹慎使用Java8的默認方法

2020-03-24 12:40lijiao JAVA教程

為什么要謹慎使用Java8的默認方法?本文給出了為什么要慎用Java8默認方法的原因,解釋的很詳細,感興趣的朋友可以參考一下

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
interface SimpleInput {
 void foo();
 void bar();
}
 
abstract class SimpleInputAdapter implements SimpleInput {
 @Override
 public void bar() {
 // some default behavior ...
 }
}

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
class MyInput extends SimpleInputAdapter{
 @Override
 public void foo() {
 // do something ...
 }
 @Override
 public void bar() {
 super.bar();
 // do something additionally ...
 }
}

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

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

?
1
2
3
4
5
6
7
interface SimpleInput {
 void foo();
 default void bar() {
 // some default behavior
 }
}}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
class MyInput extends ThirdPartyBaseClass implements SimpleInput {
 @Override
 public void foo() {
 // do something ...
 }
 @Override
 public void bar() {
 SimpleInput.super.foo();
 // do something additionally ...
 }
}

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

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

?
1
2
3
4
5
6
7
8
9
interface ComplexInput extends SimpleInput {
 void qux();
 @Override
 default void bar() {
 SimpleInput.super.bar();
 // so complex, we need to do more ...
 }
}

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

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

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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(); 錯誤
 }
 
 
}

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

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

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

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 91肥熟国产老肥熟在线 | 成人夜视频寂寞在线观看 | 色老板在线视频 | 色婷婷在线视频 | 精品久久亚洲 | 日本在线看免费 | 久久AV喷吹AV高潮欧美 | 免费看3d小舞被躁视频网站 | 亚洲女同在线观看 | 精新精新国产自在现 | japaneseles女同专区 | 国产在线一区二区视频 | 大又大又粗又爽女人毛片 | 精品一区二区三区五区六区七区 | 婷婷中文网 | 三级黄片毛片 | 国产成人在线小视频 | 韩国理论三级在线观看视频 | 96免费精品视频在线 | 四虎影院在线免费观看视频 | 成年人黄色录像 | 国产女乱淫真高清免费视频 | 国产播放啪视频免费视频 | 国产精品视频二区不卡 | 91中文在线 | 成人精品一区二区三区中文字幕 | 亚洲欧美一区二区三区在饯 | 久久久久久久久性潮 | 美国xaxwaswaskino 美妇在线 | 国内精品久久久久久野外 | 久久精品动漫99精品动漫 | 国产午夜精品一区二区三区 | 免费视频左左视频 | 极品丝袜乱系列在线阅读 | 40岁女人三级全黄 | 成人国产午夜在线视频 | 成人伊人青草久久综合网破解版 | 国产福利一区二区三区四区 | 香蕉eeww99国产精选播放 | 国产精品啪啪 | 日韩精品免费一区二区三区 |