1. 程式人生 > >JAVA 8 預設方法-Default Methods

JAVA 8 預設方法-Default Methods

什麼是預設方法-Default Methods?簡單的說,就是可以在介面中定義一個已實現方法,且該介面的實現類不需要實現該方法.如下示例:

interface GreetingService  {
        void sayMessage(String message);
        
        //可以在介面中定義預設方法
        default void sayHello(){
            System.out.println("Hello");
        }
    }
    
    //實現類不需要實現介面中的預設方法
    class GreetingServiceImpl implements GreetingService{
        @Override
        public void sayMessage(String message)
        {

        }
    }
1、為什麼要有預設方法?

主要是為了方便擴充套件已有介面;如果沒有預設方法,加入給JDK中的某個介面新增一個新的抽象方法,那麼所有實現了該介面的類都得修改,影響將非常大。

使用預設方法,可以給已有介面新增新方法,而不用修改該介面的實現類。當然,介面中新新增的預設方法,所有實現類也會繼承該方法。

舉個例子,在Java 8的Iterable介面中,新增了一個預設方法forEach,也正因為forEach是預設方法,才不用修改所有Iterable介面的實現類。

Iterable介面新增的forEach方法如下(入參是一個函式式介面,因此支援Lambda表示式):

default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
}

因為Collection介面繼承了Iterable介面,所以我們可以在集合類中使用forEach方法,如下,這裡使用了方法引用(一種更加緊湊的Lambda表示式)

List<String> list = new ArrayList<String>();
        list.add("001");
        list.add("002");
        list.forEach(System.out::println);
可見,我們在未破壞Iterable介面實現類的前提下,給Iterable介面的所有實現類添加了一個新方法forEach,這在Java 8之前是不可能的。

2、重寫Override預設方法
如果子類沒有重寫父介面預設方法的話,會直接繼承父介面預設方法的實現;
如果子類重寫父介面預設方法為普通方法,則與普通方法的重寫類似;
如果子類(介面或抽象類)重寫父介面預設方法為抽象方法,那麼所有子類的子類需要實現該方法;

3、關於預設方法呼叫衝突

因為一個類是可以實現多個介面的,如果多個介面定義了同樣的預設方法,那麼子類如何呼叫父類的預設方法呢?具體呼叫流程如下:

1)首先,如果子類覆蓋了父類的預設方法,那麼什麼也不用想,直接使用呼叫子類覆蓋後的方法;

2)其次,優先選擇呼叫更加具體的介面預設方法,什麼意思呢,舉個例子,如果A1介面繼承A介面,那麼A1介面相對A介面就更加具體,當C類實現了A1介面的時候,就優先呼叫A1介面的預設方法;

3)最後,如果C類同時實現A1介面和A2介面,且A1和A2有同名的預設方法,那麼選擇哪個介面的預設方法呢?答案是編譯器報錯,提示定義了重名的方法,快速修復方式是覆蓋其中的一個即可;

關於這塊內容,在網上看到一段有意思的程式碼,如下,知道為什麼會報錯嗎?如果刪除InterfaceB中的foo方法,是否還會報錯?往InterfaceC中新增foo方法又會怎樣?