JAVA 8 預設方法-Default Methods
阿新 • • 發佈:2019-02-08
什麼是預設方法-Default Methods?簡單的說,就是可以在介面中定義一個已實現方法,且該介面的實現類不需要實現該方法.如下示例:
1、為什麼要有預設方法?interface GreetingService { void sayMessage(String message); //可以在介面中定義預設方法 default void sayHello(){ System.out.println("Hello"); } } //實現類不需要實現介面中的預設方法 class GreetingServiceImpl implements GreetingService{ @Override public void sayMessage(String message) { } }
主要是為了方便擴充套件已有介面;如果沒有預設方法,加入給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方法又會怎樣?