Java8新特性:介面的預設方法與介面的靜態方法,java8新特性
介面的定義
介面的作用是定義該類型的執行個體要具有的功能,也就是必須執行哪些工作,並且不需要關心這些工作是怎麼具體進行的。介面定義的方法沒有方法體,並且介面不允許定義執行個體變數。如果一個類實現了這個介面就必須實現重寫介面的所有方法。介面如下:
1 public interface MyInterface{2 int getInt();3 }
介面的優勢
介面的設計主要是為了支援運行時動態方法的解析。通常情況下,為了能夠從一個類中調用另外一個類的方法,編譯時間這兩個類都需要存在,這樣的要求造成了類系統的不可擴充性。設計介面的目的就是為了增強類的擴充性,具體參考如下:
public interface MyInterface{ int getInt(); }
public class MyInterfaceImpl implements MyInterface{ @Override public int getInt(){ return 6; } }
public classMain{ public static void main(String[] args){ MyInterface my = null; // 根據工廠或者其他方式擷取MyInterfaceImpl或者MyInterfaceImpl1的執行個體 my.getInt(); } }
上述代碼中,編譯期間,編譯器無法確定當前"my"對象的實作類別的哪個。只有在運行期間,建立對應的執行個體時,才可以確定,這樣就更好的實現了多態的特性。
類與介面的區別
- 類中可以定義成員變數,但是介面中不允許存在成員變數
- 介面中所有方法都沒有具體實現(Java8以前這種定義是正確的,但是在JAVA8以後增加了介面的預設實現方法)
抽象類別比較特殊,抽象類別中既可以定義成員變數,又可以像介面一樣定義抽象方法,由子類去完成方法的細節。如果一個類只是實現了介面中的部分方法定義,那麼該類必須聲明為抽象類別。這種編程模式經常被使用。如:Spring的AbstractBeanFactory間接的實現了BeanFactory以及其他介面中通用功能,其他方法交由後續子類實現。在我們實際開發中,也經常會針對Service以及Dao做一個抽象介面,然後開發一個抽象類別,將通用功能實現,例如dao中的增刪改查翻頁等,對於業務特有內容,則交由後續子類實現。
JAVA8中介面的預設方法
預設方法允許介面方法定義預設實現,子類方法不必須實現此方法而就可以擁有該方法及實現。如下:
public interface DefaultFuncInter { int getInt(); default String getString(){ return "Default String"; }}
預設方法的優勢
預設方法主要優勢是提供了一種擴充介面的方法,而不破壞現有代碼。如果一個已經投入使用的介面需要擴充一個新的方法,在JDK8以前,我們必須再該介面的所有實作類別中都添加該方法的實現,否則編譯會出錯。如果實作類別數量很少且我們有修改的許可權,可能工作量會少,但是如果實作類別很多或者我們沒有修改代碼的許可權,這樣的話就很難解決了。而預設方法提供了一個實現,當沒有顯式提供時就預設採用這個實現,這樣新添加的介面就不會破壞現有的代碼。
預設方法另一個優勢是該方法是可選的,子類可以根據不同的需求而且經override或者採用預設實現。例如我們定義一個集合幾口,其中有增、刪、改等操作,如果我們的實作類別90%都是以數組儲存資料,那麼我們可以定義針對這些方法給出預設實現,而對於其他非數組集合或者有其他類似業務,可以選擇性複寫介面中預設方法。(由於介面不允許有成員變數,所以本樣本旨在說明預設方法的優勢,並不具有生產可能性)具體參照如下代碼:
/** * 定義介面,並包含預設實現方法 */ public interface CollectionDemoInter { //增加預設實現 default void addOneObj(Object object){ System.out.println("default add"); } //刪除預設實現 default void delOneObj(Object object){ System.out.println("default del"); } //更新預設實現 default void updateOneObj(Object object){ System.out.println("default del"); } //介面定義需要實現方法 String showMsg();}
/** * 基於數組的集合實作類別,增刪改使用預設方法 */ public class Collection4Array implements CollectionDemoInter { @Override public String showMsg() { return null; } }
/** * 特殊集合,不允許刪除元素 */ public class NodelCollection implements CollectionDemoInter { @Override public String showMsg() { return null; } @Override public void delOneObj(Object object){ System.out.println("none del"); } }
通過上述代碼,大家可以很清楚的發現,如果在介面中定義預設方法,則子類不需要必須實現該預設實現,如果有特殊需求或者需要,則可以Override該實現。
需要注意
- 如果一個類實現兩個或兩個以上介面,並且多個介面中包含統一預設方法,此時,編譯器將報錯。這種情況,我們必須讓子類Override該方法,否則無法編譯通過。
- 在所有的情況,類實現的優先順序高於介面的預設實現,也就是先使用自己類中定義的方法或者是父類中的方法。
- 如果是一個介面繼承了另外一個介面,2個介面中也包含相同的預設方法,那麼繼承介面的版本具有更高的優先順序。比如A擴充了B介面,那麼優先使用A類裡面的test方法。
- 通過使用super,可以顯式的引用被繼承介面的預設實現,文法如下:InterfaceName.super.methodName()。
介面中的靜態方法
java8中為介面新增了一項功能:定義一個或者更多個靜態方法。類似於類中的靜態方法,介面定義的靜態方法可以獨立於任何對象調用。所以,在調用靜態方法時,不需要實現介面,也不需要介面的執行個體,也就是說和調用類的靜態方法的方式類似。文法如:介面名字.靜態方法名。
interface A { static String getName() { return "介面A。。。"; } }public class Test implements A { public static void main(String[] args) { System.out.println(A.getName()); } }
注意,實現介面的類或者子介面不會繼承介面中的靜態方法。static不能和default同時使用。在java8中很多介面中都增加了靜態方法,比如下面代碼:
public class Test { public static void test(List<String> list) { //直接使用Comparator的靜態方法 list.sort(Comparator.comparing(String::length)); } public static void main(String[] args) { List<String> list = Lists.newArrayList("122","2","32"); test(list); for (String str : list) { System.out.println(str); } } }