激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

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

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

服務器之家 - 編程語言 - JAVA教程 - 解析Java中的默認方法

解析Java中的默認方法

2019-12-26 13:13goldensun JAVA教程

這篇文章主要介紹了Java中的默認方法,包括繼承和調用等Java入門學習中的基礎知識,需要的朋友可以參考下

 為什么有默認方法?

Java 8 就要來臨,盡管發布期限已經被推遲, 我們仍非常確信在它最終發布的時候會支持lambdas 表達式。 前面提到過,我們之前關于這個主題已經討論了不少,不過,lambdas表達式并不是Java 8中唯一改變的游戲規則。


假設Java 8 已經發布并且包含了lambda。現在你打算用一下lambda,最明顯的應用場景莫過于對collection的每一個元素應用lambda。
 

?
1
2
List<?> list = …
list.forEach(…); // 這就是lambda代碼

在java.util.List或者java.util.Collection接口里都找不到forEach的定義。通常能想到的解決辦法是在JDK里給相關的接口添加新的方法及實現。然而,對于已經發布的版本,是沒法在給接口添加新方法的同時不影響已有的實現。

因此,如果在Java 8里使用lambda的時候,因為向前兼容的原因而不能用于collection庫,那有多糟糕啊。


由于上述原因,引入了一個新的概念。虛擬擴展方法,也即通常說的defender方法, 現在可以將其加入到接口,這樣可以提供聲明的行為的默認實現。

簡單的說,Java的接口現在可以實現方法了。默認方法帶來的好處是可以為接口添加新的默認方法,而不會破壞接口的實現。

在我看來,這并非那種每天都會用到的Java特性,但是它絕對能讓Java的Collections API可以很自然的使用lambda。

最簡單的例子

讓我們看一個最簡單的例子:一個接口A,Clazz類實現了接口A。
 

?
1
2
3
4
5
6
7
8
public interface A {
  default void foo(){
    System.out.println("Calling A.foo()");
  }
}
 
public class Clazz implements A {
}

代碼是可以編譯的,即使Clazz類并沒有實現foo()方法。在接口A中提供了foo()方法的默認實現。

使用這個例子的客戶端代碼:
 

?
1
2
Clazz clazz = new Clazz();
clazz.foo(); // 調用A.foo()

多重繼承?

有一個常見的問題:人們會問 當他們第一次聽到關于默認方法的新的特性時 “如果一個類實現了兩個接口,并且兩個接口都用相同的簽名定義了默認方法,這該怎么辦?”讓我們用先前的例子來展示這個解決方案:
 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public interface A {
  default void foo(){
    System.out.println("Calling A.foo()");
  }
}
 
public interface B {
  default void foo(){
    System.out.println("Calling B.foo()");
  }
}
 
public class Clazz implements A, B {
}

這段代碼不能編譯 有以下原因:

java:class Clazz 從types A到B給foo()繼承了不相關的默認值

為了修復這個,在Clazz里我們不得不手動解決通過重寫沖突的方法:
 

?
1
2
3
public class Clazz implements A, B {
  public void foo(){}
}

但是如果我們想從接口A中調用默認實現方法foo(),而不是實現我們自己的方法,該怎么辦呢?這是有可能的,引用A中的foo(),如下所示:
 

?
1
2
3
4
5
public class Clazz implements A, B {
  public void foo(){
    A.super.foo();
  }
}

現在我不能十分確信我喜歡這個最終方案。也許它比在簽名里聲明默認方法的實現更為簡練,正如在默認方法規范的第一手稿里所聲明的:
 

?
1
2
3
public class Clazz implements A, B {
  public void foo() default A.foo;
}

但是這確實更改了語法,難道不是嗎?它看起來更像一個接口的方法聲明而不是實現。假若接口A和接口B定義了許多相互沖突的默認方法,而我愿意使用所有接口A的默認方法解決沖突,那又如何呢?目前我不得不一個接著一個的解決沖突,改寫每一對沖突的方法。這可能需要大量的工作和書寫大量的模板代碼。

我估計解決沖突的方法需要進行大量的討論,不過看起來創建者決定接受這無法避免的災難。

真實的例子

默認方法實現的真實例子可以在 JDK8早期打的包中找到。回到集合的forEach方法的例子中, 我們可以發現在java.lang.Iterable接口中,它的默認實現如下:
 

?
1
2
3
4
5
6
7
8
9
10
11
@FunctionalInterface
public interface Iterable<T> {
  Iterator<T> iterator();
 
  default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
      action.accept(t);
    }
  }
}

forEach 使用了一個java.util.function.Consumer功能接口類型的參數,它使得我們可以傳入一個lambda表達式或者一個方法引用,如下:
 

?
1
2
List<?> list = …
list.forEach(System.out::println);

方法調用
讓我們看一下實際上是如何調用默認的方法的。如果你不熟悉這個問題,那么你可能有興趣閱讀一下Rebel實驗室有關Java字節的報告。

從客戶端代碼的視角來看,默認的方法僅僅是常見的虛擬方法。因此名字應該是虛擬擴展方法。因此對于把默認方法實現為接口的簡單例子類來說,客戶端代碼將在調用默認方法的地方自動調用接口。
 

?
1
2
3
4
5
A clazz = new Clazz();
clazz.foo(); // invokeinterface foo()
 
Clazz clazz = new Clazz();
clazz.foo(); // invokevirtual foo()

如果默認方法的沖突已經解決,那么當我們修改默認方法并指定調用其中一個接口時候,invokespecial將給我們指定具體調用哪個接口的實現。
 

?
1
2
3
4
5
public class Clazz implements A, B {
  public void foo(){
    A.super.foo(); // invokespecial foo()
  }
}

下面是javap的輸出:

?
1
2
3
4
5
public void foo();
Code:
0: aload_0
1: invokespecial #2 // InterfaceMethod A.foo:()V
4: return

正如你看到的:invokespecial指令用來調用接口方法foo()。從字節碼的視角來看,這仍是新鮮的事情,因為以前你只能通過指向一個類(父類)的而不是指向一個接口的super來調用方法。

最后…

默認方法是對Java語言的有趣補充 – 你可以把他們看做是lambdas表達式和JDK庫之間的橋梁。默認表達式的主要目標是使標準JDK接口得以進化,并且當我們最終開始使用Java 8的lambdas表達式時,提供給我們一個平滑的過渡體驗。誰知道呢,也許將來我們會在API設計中看到更多的默認方法的應用。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 中文字幕精品一区久久久久 | 日美黄色片 | av免费不卡国产观看 | 91香蕉国产亚洲一区二区三区 | 国产免费一区二区三区在线能观看 | 日本在线高清 | 91久久国产综合精品女同国语 | 蜜桃久久一区二区三区 | 狠狠操天天射 | 日韩不卡一区二区 | 日韩欧美色综合 | 久久久久性视频 | 狠狠操天天操 | 午色影院 | 国毛片 | 91看片网页 | 午夜精品成人一区二区 | 爽毛片 | 嫩草影院在线观看网站成人 | 草莓视频久久 | 黄色免费在线网站 | 欧美成人一区二区三区电影 | 久久久国产精品电影 | 亚洲综合网站 | 人人舔人人射 | 国产成人av免费 | 二级大黄大片高清在线视频 | 精品久久久久久国产 | 奶子吧naiziba.cc免费午夜片在线观看 | 成人黄色小视频网站 | 91看片网页 | 亚洲成人午夜精品 | 精品久久中文字幕 | 黄色片在线观看网站 | 视频在线色| 免费黄色av| 免费在线观看亚洲 | 中文字幕免费在线观看视频 | 国av在线 | www.99久久久 | 国产精品美女一区二区 |