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);  
        }  
    }  
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM