傳統上,Java程序的接口是將相關方法按照預約組合到一塊兒的方式。實現接口的類必須爲接口中定義的方法提供一個實現,或者從父類中集成它的實現。可是,一旦類庫的設計者須要更新接口,向接口中加入新的方法時候,這種方式就會出現問題。現存的類爲了適應新的接口約定也要進行修改。java
Java 8爲了解決這個問題,如今接口支持在生命方法的同時提供實現,Java 8 容許在接口內聲明靜態方法,Java 8 容許在接口中建立默認方法。默認方法能夠指定全部實現類的默認實現。這種模式可讓你平滑的進行接口的優化。dom
List中的sort方法就是一個靜態方法:函數
default void sort(Comparator<? super E> c) { Object[] a = this.toArray(); Arrays.sort(a, (Comparator) c); ListIterator<E> i = this.listIterator(); for (Object e : a) { i.next(); i.set((E) e); } }
經過default關鍵字來在接口中定義默認方法。能夠直接調用sort,對列表進行排序:優化
Arrays.asList(1,2,3,5,54).sort(Comparator.naturalOrder());
Comparator.naturalOrder是一個靜態方法,它返回了一個Comparator對象,按照天然序列對其中的元素進行排序this
public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() { return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE; }
Collection中的Stream方法也是一個靜態方法:spa
default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); }
Stream是經過StreamSupport調用了一個stream方法,來返回的Stream對象。而且,如今你知道spliterator 是怎麼來的了吧,它也是Collection接口的一個默認方法。設計
默認方法的引用就是爲了解決Java API這樣的類庫演進問題。由於向接口中增長方法會致使全部實現類受害。它們也都要進行更新。默認方法可讓全部實現類自動繼承接口的一個默認實現。code
定義默認方法對象
使用default前綴,並加入方法體便可,好比定義一個sized接口:blog
public interface Sized { int size(); default boolean isEmpty(){ return size() == 0; } }
全部的實現類,都會自動繼承isEmpty的實現。
Java8中的抽象類和抽象接口
抽象接口是指函數式接口中 包含的方法->如 Predicate中的test。
一個類只能繼承一個抽象類,可是一個類能夠實現多個接口。
一個抽象類能夠設置實例變量,接口不能有實例變量。
可選方法
有時,一個類實現了接口,不過卻刻意的將一些方法的實現留白。以Iterator接口爲例,Iterator接口定義了hasNext、next還有remove方法。Java 8 以前,因爲用戶一般不會使用該方法,remove方法常被忽略。所以,實現了Iterator接口的類一般會爲remove方法放置一個空的實現,這些都是毫無用處的模板代碼。
採用默認方法以後,你能夠爲這種類型的方法提供一個默認的實現,這樣實體類就無需在本身的實現中顯示的提供一個空方法。
interface Iterator<T> {
boolean hasNext(); T next(); default void remove() { throw new UnsupportedOperationException(); } }
經過這種方式,能夠減小不少無效的模板代碼。無需再實現remove方法。
行爲的多繼承
默認方法以前是沒法優雅的實現多繼承的,讓一個類從多個來源重用代碼的能力。由於java的類只能繼承單一的類,可是一個類能夠實現多個接口。好比ArrayList類的定義:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
它繼承了一個類,實現了4個接口。所以ArrayList其實是7個類型的直接子類。在某種程度上,咱們早就有了多繼承。
因爲Java 8中的接口也能夠提供實現,類能夠從多個接口中繼承他們的行爲。
好比你要實現一個接口,有的類須要能夠放大縮小,不須要改變形狀。有的類須要改變形狀 不須要放大縮小。這時能夠將 放大縮小放在一個接口中提供一個實現,放大縮小放在一個接口中,而後在須要的類中 各自實現各自的接口。繼承各自的默認實現。不要都放在一個接口中。
解決衝突的規則
咱們知道,一個類只能夠繼承一個類,可是能夠實現多個接口。隨着Java 8 帶來的默認方法的加入,有可能會出現類或者多個接口中的默認方法出現重複的問題。在這種狀況下,
1.類的方法優先級最高,類或父類中聲明的方法的優先級高於任何聲明的默認方法的優先級。
2.若有沒法依據第一條進行判斷,那麼子接口的優先級更高:函數簽名相同時,優先選擇擁有最具體實現的默認方法的接口,若是B實現了A,那麼A就更具體。
3.最後,若是仍是沒法判斷,繼承了多個接口的類必須經過顯示覆蓋和調用指望的方法,顯示的選擇使用哪個默認方法的實現。
public class C implements B,A{ void hello(){ //顯示指定哪一個接口中的同名方法 B.supper.hello(); } }
小結
1.Java 8中的接口能夠經過默認方法和靜態方法提供代碼的實現。
2.默認方法的開頭以關鍵字default修飾,方法體與常規類的方法相同。
3.向發佈的接口添加抽象方法不是源碼兼容的。
4.默認方法的出現能幫助庫的設計者之後向兼容的方式演進API。
5.默認方法能夠用於建立可選方法和行爲的多繼承。
6.當函數名重複時,能夠按照優先級進行判斷,類和父類實現最高,其餘沒法肯定時,能夠顯示指定調用哪一個。