Java 8 (8) 默認方法

  傳統上,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.當函數名重複時,能夠按照優先級進行判斷,類和父類實現最高,其餘沒法肯定時,能夠顯示指定調用哪一個。

相關文章
相關標籤/搜索