java8中接口方法(默認方法、static靜態方法)

1、概述

以前,接口裏的方法要求全部是抽象方法,java8以後允許在接口裏定義默認方法和類方法。不同的是:
默認方法可以通過實現接口的類實例化的對象來調用,而類方法就相對於工具方法了。需要注意的是,此處的靜態方法只能被public修飾(或者省略不寫),不能是private或者protected

java8可以說是jdk版本的一次重大升級,給我們也帶來了非常多的新特性,而本文就針對於java8中很重要的新特性之一:接口方法。來討論一下平時使用中可能遇到的問題

2、栗子

大家都知道,在jdk8之後,接口裏面咱們都可以寫具體的方法了,但這方法比較特殊,只能是靜態方法或者默認方法。這又讓我們有更好的設計,可以設計出更加高內聚的代碼,更加方便的管理封裝。

public interface MyInter {
    default void df(){    //聲明一個接口的默認方法

        System.out.println("i'am default f");
        sf();        //調用本接口的類方法
    }
    static void sf(){    //聲明一個接口的類方法

        System.out.println("i'am static f");
    }
}

如上,本接口的默認方法還可以直接調用本類的靜態方法。

默認方法的主要優勢是提供一種拓展接口的方法,而不破壞現有代碼。加入我們有一個已經投入使用接口需要拓展一個新的方法,在JDK8以前,如果爲一個使用的接口增加一個新方法,則我們必須在所有實現類中添加該方法的實現,否則編譯會出現異常。如果實現類數量少並且我們有權限修改,可能會工作量相對較少。如果實現類比較多或者我們沒有權限修改實現類源代碼,這樣可能就比較麻煩。而默認方法則解決了這個問題,它提供了一個實現,當沒有顯示提供其他實現時就採用這個實現。這樣新添加的方法將不會破壞現有代碼。
默認方法的另一個優勢是該方法是可選的,子類可以根據不同的需求Override默認實現

咱們先定義兩個接口,下面要使用的:

interface DemoInterface {
    default void doSomething() {
        System.out.println("默認方法-->demo");
    }
}

interface Demo1Interface {
    default void doSomething() {
        System.out.println("默認方法-->demo1");
    }
}

然後定義一個實現類

class AA implements DemoInterface {

    public static void main(String[] args) {
        AA aa = new AA();
        aa.doSomething(); //默認方法-->demo
    }
}

輸出默認方法的輸出,但如果AA實現了兩個接口,並且這兩個接口裏有有同名默認方法呢?
這裏寫圖片描述
我們會發現,編譯報錯了,強制要求我們必須實現這個方法。

class AA implements DemoInterface, Demo1Interface {

    @Override
    public void doSomething() {
        Demo1Interface.super.doSomething();
    }

    public static void main(String[] args) {
        AA aa = new AA();
        aa.doSomething(); //默認方法-->demo1
    }
}

再一個情況,接口之間存在繼承關係,然後存在同名情況

interface DemoInterface {
    default void doSomething() {
        System.out.println("默認方法-->demo");
    }
}

interface Demo1Interface extends DemoInterface {

    default void doSomething() {
        System.out.println("默認方法-->demo1");
    }
}

class AA implements Demo1Interface {

    public static void main(String[] args) {
        AA aa = new AA();
        aa.doSomething(); //默認方法-->demo1
    }
}

我們發現,有點類似於Maven的原則:採取就近原則

綜上,咱們經過實驗得出如下結論:

  1. 繼承的父類和實現的接口中有相同簽名的方法時,優先使用父類的方法。
  2. 當接口的父接口中也有同樣的默認方法時,就近原則調用子接口的方法。
  3. 當實現的多個接口中有相同簽名的方法時,必須在實現類中通過重寫方法解決衝突問題,否者無法通過編譯,在重寫的方法中可以通過 接口名.super.方法名(); 的方式顯示調用需要的方法。

如果一個類既extend了父類,又實現了接口。如果出現同名方法,那就遵循類優先原則。

3、使用場景

接口是設計模式中一種開閉原則的體驗,而java8賦予了接口新的特性,使得接口使用起來更加的得心應手了,這也有助於我們更加內聚自己的代碼結構了。比如collection即可類和接口,排序接口,把很多工具方法都放到接口裏了。

4、最後

多多使用新的特性,就能多多提高生產效率(編碼效率)。另外,我可以引出一個提問:爲什麼java的接口裏的屬性必須是static的?並且要求必須是final的呢?這個留給大家自己做思考。。。算了,順便奉上吧:

  1. 接口中的數據對所有實現類只有一份,所以是static
  2. 要使實現類爲了向上轉型成功,所以必須是final的(接口不能被實例化,所以接口裏面如果是變量的話不會被賦初始值這樣就會出問題,所以必須是final的。其實還是爲了安全考慮的) 這樣接口也能起到一定的模版的作用。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章