摘要:類或父類中聲明的方法的優先級高于任何聲明為默認方法的優先級。只有聲明了一個默認方法。由于比更加具體,所以編譯器會選擇中聲明的默認方法。
如果在現存的接口上引入了非常多的新方法,所有的實現類都必須進行改造,實現新方法,為了解決這個問題,Java 8為了解決這一問題引入了一種新的機制。Java 8中的接口現在支持在聲明方法的同時提供實現,這聽起來讓人驚訝!通過兩種方式可以完成這種操作。其一,Java 8允許在接口內聲明靜態方法。其二,Java 8引入了一個新功能,叫默認方法,通過默認方法你可以指定接口方法的默認實現。
靜態方法可以存在于接口內部一、不斷演進的API
默認方法試它讓類庫的設計者放心地改進應用程序接口,無需擔憂對遺留代碼的影響,這是因為實現更新接口的類現在會自動繼承一個默認的方法實現。
二、概述默認方法不同類型的兼容性:二進制、源代碼和函數行為
變更對Java程序的影響大體可以分成三種類型的兼容性,分別是:二進制級的兼容、源代碼級的兼容,以及函數行為的兼容。向接口添加新方法是二進制級的兼容,但最終編譯實現接口的類時卻會發生編譯錯誤。二進制級的兼容性表示現有的二進制執行文件能無縫持續鏈接(包括驗證、準備和解析)和運行。比如,為接口添加一個方法就是二進制級的兼容,這種方式下,如果新添加的方法不被調用,接口已經實現的方法可以繼續運行,不會出現錯誤。
簡單地說,源代碼級的兼容性表示引入變化之后,現有的程序依然能成功編譯通過。
最后,函數行為的兼容性表示變更發生之后,程序接受同樣的輸入能得到同樣的結果。比如,為接口添加新的方法就是函數行為兼容的,因為新添加的方法在程序中并未被調用(抑或該接口在實現中被覆蓋了)。
默認方法由default修飾符修飾,并像類中聲明的其他方法一樣包含方法體。比如,你可以像下面這樣在集合庫中定義一個名為Sized的接口,在其中定義一個抽象方法size,以及一個默認方法isEmpty:
public interface Sized { int size(); default boolean isEmpty() { return size() == 0; } }
第3章介紹的很多函數式接口,比如Predicate、Function以及Comparator也引入了新的默認方法,比如Predicate.and或者Function.andThen(記住,函數式接口只包含一個抽象方法,默認方法是種非抽象方法)。
個抽象類可以通過實例變量(字段)保存一個通用狀態,而接口是不能有實例變量的。三、默認方法的使用模式 1.可選方法
你很可能也碰到過這種情況,類實現了接口,不過卻刻意地將一些方法的實現留白。我們以Iterator接口為例來說。Iterator接口定義了hasNext、next,還定義了remove方法。Java 8之前,由于用戶通常不會使用該方法,remove方法常被忽略。因此,實現Interator接口的類通常會為remove方法放置一個空的實現,這些都是些毫無用處的模板代碼。
采用默認方法之后,你可以為這種類型的方法提供一個默認的實現,這樣實體類就無需在自己的實現中顯式地提供一個空方法。比如,在Java 8中,Iterator接口就為remove方法提供了一個默認實現,如下所示:
interface Iterator2.行為的多繼承{ boolean hasNext(); T next(); default void remove() { throw new UnsupportedOperationException(); }
類型的多繼承
利用正交方法的精簡接口
組合接口
繼承不應該成為你一談到代碼復用就試圖倚靠的萬精油。比如,從一個擁有100個方法及字段的類進行繼承就不是個好主意,因為這其實會引入不必要的復雜性。你完全可以使用代理有效地規避這種窘境,即創建一個方法通過該類的成員變量直接調用該類的方法。四、解決沖突的規則 1.解決問題的三條規則
如果一個類使用相同的函數簽名從多個地方(比如另一個類或接口)繼承了方法,通過三條規則可以進行判斷。
(1)類中的方法優先級最高。類或父類中聲明的方法的優先級高于任何聲明為默認方法的優先級。
(2)如果無法依據第一條進行判斷,那么子接口的優先級更高:函數簽名相同時,優先選擇擁有最具體實現的默認方法的接口,即如果B繼承了A,那么B就比A更加具體。
(3)最后,如果還是無法判斷,繼承了多個接口的類必須通過顯式覆蓋和調用期望的方法,顯式地選擇使用哪一個默認方法的實現。
2.沖突及如何顯式地消除歧義對于上面提到的第三種情況,解決這種兩個可能的有效方法之間的沖突,沒有太多方案;你只能顯式地決定你希望在C中使用哪一個方法。為了達到這個目的,你可以覆蓋類C中的hello方法,在它的方法體內顯式地調用你希望調用的方法。Java 8中引入了一種新的語法X.super.m(…),其中X是你希望調用的m方法所在的父接口。舉例來說,如果你希望C使用來自于B的默認方法,它的調用方式看起來就如下所示:
public class C implements B, A { void hello(){ B.super.hello(); } }3.菱形繼承問題
讓我們考慮最后一種場景,它亦是C++里中最令人頭痛的難題。
public interface A{ default void hello(){ System.out.println("Hello from A"); } } public interface B extends A { } public interface C extends A { } public class D implements B, C { public static void main(String... args) { new D().hello(); } }
這種問題叫“菱形問題”,因為類的繼承關系圖形狀像菱形。這種情況下類D中的默認方法到底繼承自什么地方 ——源自B的默認方法,還是源自C的默認方法?實際上只有一個方法聲明可以選擇。只有A聲明了一個默認方法。由于這個接口是D的父接口,代碼會打印輸出“Hello from A”。
現在,我們看看另一種情況,如果B中也提供了一個默認的hello方法,并且函數簽名跟A中的方法也完全一致,這時會發生什么情況呢?根據規則(2),編譯器會選擇提供了更具體實現的接口中的方法。由于B比A更加具體,所以編譯器會選擇B中聲明的默認方法。如果B和C都使用相同的函數簽名聲明了hello方法,就會出現沖突,正如我們之前所介紹的,你需要顯式地指定使用哪個方法。順便提一句,如果你在C接口中添加一個抽象的hello方法(這次添加的不是一個默認方法),會發生什么情況呢?你可能也想知道答案。
public interface C extends A { void hello(); }
這個新添加到C接口中的抽象方法hello比由接口A繼承而來的hello方法擁有更高的優先級,因為C接口更加具體。因此,類D現在需要為hello顯式地添加實現,否則該程序無法通過編譯。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74296.html
摘要:但返回的是一個類型的對象,這意味著操作的結果是一個類型的對象。反之,如果對象存在,這次調用就會將其作為函數的輸入,并按照與方法的約定返回一個對象。 一、Optional 類入門 Java 8中引入了一個新的類java.util.Optional。變量存在時,Optional類只是對類簡單封裝。變量不存在時,缺失的值會被建模成一個空的Optional對象,由方法Optional.empt...
摘要:實戰讀書筆記第一章從方法傳遞到接著上次的,繼續來了解一下,如果繼續簡化代碼。去掉并且生成的數字是萬,所消耗的時間循序流并行流至于為什么有時候并行流效率比循序流還低,這個以后的文章會解釋。 《Java8實戰》-讀書筆記第一章(02) 從方法傳遞到Lambda 接著上次的Predicate,繼續來了解一下,如果繼續簡化代碼。 把方法作為值來傳遞雖然很有用,但是要是有很多類似與isHeavy...
摘要:利用前面所述的方法,這個例子可以用方法引用改寫成下面的樣子構造函數引用對于一個現有構造函數,你可以利用它的名稱和關鍵字來創建它的一個引用。 第三章 Lambda表達式 函數式接口 函數式接口就是只定義一個抽象方法的接口,哪怕有很多默認方法,只要接口只定義了一個抽象方法,它就仍然是一個函數式接口。 常用函數式接口 showImg(https://segmentfault.com/img...
摘要:但是,最好使用差異化的類型定義,函數簽名如下其實二者說的是同一件事。后者的返回值和初始函數的返回值相同,即。破壞式更新和函數式更新的比較三的延遲計算的設計者們在將引入時采取了比較特殊的方式。四匹配模式語言中暫時并未提供這一特性,略。 一、無處不在的函數 一等函數:能夠像普通變量一樣使用的函數稱為一等函數(first-class function)通過::操作符,你可以創建一個方法引用,...
摘要:正確使用并行流錯用并行流而產生錯誤的首要原因,就是使用的算法改變了某些共享狀態。高效使用并行流留意裝箱有些操作本身在并行流上的性能就比順序流差還要考慮流的操作流水線的總計算成本。 一、并行流 1.將順序流轉換為并行流 對順序流調用parallel方法: public static long parallelSum(long n) { return Stream.iterate(1L...
摘要:比如,你可以建立一個,選出熱量超過卡路里的頭三道菜請注意也可以用在無序流上,比如源是一個。跳過元素流還支持方法,返回一個扔掉了前個元素的流。一般來說,應該使用來對這種流加以限制,以避免打印無窮多個值。 一、篩選和切片 1.用謂詞篩選 Streams接口支持filter方法。該操作會接受一個謂詞(一個返回boolean的函數)作為參數,并返回一個包括所有符合謂詞的元素的流。例如篩選出所有...
閱讀 3459·2023-04-25 19:39
閱讀 3810·2021-11-18 13:12
閱讀 3637·2021-09-22 15:45
閱讀 2437·2021-09-22 15:32
閱讀 722·2021-09-04 16:40
閱讀 3731·2019-08-30 14:11
閱讀 1890·2019-08-30 13:46
閱讀 1567·2019-08-29 15:43