Java8接口:靜態(tài)方法與默認(rèn)方法

閱讀原文: Java8接口:靜態(tài)方法與默認(rèn)方法

往期文章一覽

  1. 為什么我要使用Optional ?

  2. 為什么數(shù)組下總是從0開始呢?

  3. 這種方式更優(yōu)雅,秒表計時!

Java8 接口更改包括接口中的靜態(tài)方法和默認(rèn)方法。在 Java8 之前,接口中只能有方法聲明,但是從 Java 8 開始,我們可以在接口中使用默認(rèn)方法和靜態(tài)方法。

Java 8 接口

設(shè)計接口一直是一項艱巨的工作,因為如果我們想在接口中添加其他方法,就需要在所有實現(xiàn)類中進(jìn)行更改。隨著接口的老化,實現(xiàn)它的類的數(shù)量可能會增長到無法擴(kuò)展接口的程度。這就是為什么在設(shè)計應(yīng)用程序時,大多數(shù)框架提供一個基本實現(xiàn)類,然后我們擴(kuò)展它并重寫適用于我們的應(yīng)用程序的方法。

讓我們看看默認(rèn)接口方法和靜態(tài)接口方法,以及它們在 Java8 接口更改中引入的原因。

Java 接口默認(rèn)方法

為了在 java 接口中創(chuàng)建默認(rèn)方法,我們需要在方法簽名中使用“default”關(guān)鍵字。例如:

package com.journaldev.java8.defaultmethod;

public interface Interface1 {

    void method1(String str);

    default void log(String str){
        System.out.println("I1 logging::"+str);
    }
}

注意,log(String str)是 Interface1 中的默認(rèn)方法。現(xiàn)在,當(dāng)一個類將實現(xiàn) Interface1 時,不必為接口的默認(rèn)方法提供實現(xiàn)。這個特性將幫助我們用額外的方法擴(kuò)展接口,我們只需要提供一個默認(rèn)的實現(xiàn)。

假設(shè)我們有另一個具有以下方法的接口:

package com.journaldev.java8.defaultmethod;

public interface Interface2 {

    void method2();

    default void log(String str){
        System.out.println("I2 logging::"+str);
    }
}

我們知道 Java 不允許我們繼承多個類,因為它會導(dǎo)致“菱形問題”,編譯器無法決定使用哪個超類方法。使用默認(rèn)方法時,接口也會出現(xiàn)菱形問題。因為如果一個類同時實現(xiàn)了 Interface1 和 Interface2 并且沒有實現(xiàn)公共的默認(rèn)方法,編譯器就不能決定選擇哪個方法。

擴(kuò)展多個接口是 Java 不可或缺的一部分,您可以在核心 Java 類以及大多數(shù)企業(yè)應(yīng)用程序和框架中找到它。因此,為了確保這個問題不會出現(xiàn)在接口中,必須為接口的常見默認(rèn)方法提供實現(xiàn)。因此,如果一個類同時實現(xiàn)上述兩個接口,則它必須為 log()方法提供實現(xiàn),否則編譯器將拋出編譯時錯誤。

實現(xiàn) Interface1 和 Interface2 的一個簡單類是:

package com.journaldev.java8.defaultmethod;

public class MyClass implements Interface1, Interface2 {

    @Override
    public void method2() {
    }

    @Override
    public void method1(String str) {
    }

    @Override
    public void log(String str){
        System.out.println("MyClass logging::"+str);
        Interface1.print("abc");
    }
}

關(guān)于 java 接口默認(rèn)方法的要點:

  1. Java 接口默認(rèn)方法將幫助我們擴(kuò)展接口,而不必?fù)?dān)心破壞實現(xiàn)類。

  2. Java 接口默認(rèn)方法彌補了接口和抽象類之間的差異。

  3. Java 8 接口默認(rèn)方法將幫助我們避免使用工具類,例如所有 Collections 類方法都可以在接口本身中提供。

  4. Java 接口默認(rèn)方法將幫助我們刪除基本實現(xiàn)類,我們可以提供默認(rèn)實現(xiàn),實現(xiàn)類可以選擇重寫哪個。

  5. 在接口中引入默認(rèn)方法的一個主要原因是為了增強 Java 8 中的 Collections API 以支持 lambda 表達(dá)式。

  6. 如果層次結(jié)構(gòu)中的任何類具有具有相同簽名的方法,則默認(rèn)方法將變得不相關(guān)。默認(rèn)方法不能重寫 java.lang.Object 中的方法。推理非常簡單,因為 Object 是所有 java 類的基類。因此,即使我們在接口中將 Object 類方法定義為默認(rèn)方法,它也將是無用的,因為 Object 類方法將始終被使用。這就是為什么要避免混淆,我們不能有覆蓋 Object 類方法的默認(rèn)方法。

  7. Java 接口默認(rèn)方法也稱為 Defender 方法或虛擬擴(kuò)展方法。

Java 接口靜態(tài)方法

Java 接口靜態(tài)方法與默認(rèn)方法類似,只是我們不能在實現(xiàn)類中重寫它們。這個特性有助于我們避免實現(xiàn)類中的糟糕實現(xiàn)帶來的不希望的結(jié)果。讓我們用一個簡單的例子來研究這個問題。

package com.journaldev.java8.staticmethod;

public interface MyData {

    default void print(String str) {
        if (!isNull(str))
            System.out.println("MyData Print::" + str);
    }

    static boolean isNull(String str) {
        System.out.println("Interface Null Check");

        return str == null ? true : "".equals(str) ? true : false;
    }
}

現(xiàn)在讓我們看看一個實現(xiàn)類,它的 isNull()方法的實現(xiàn)很差。

package com.journaldev.java8.staticmethod;

public class MyDataImpl implements MyData {

    public boolean isNull(String str) {
        System.out.println("Impl Null Check");
        return str == null ? true : false;
    }

    public static void main(String args[]){
        MyDataImpl obj = new MyDataImpl();
        obj.print("");
        obj.isNull("abc");
    }
}

注意,isNull(String str)是一個簡單的類方法,它沒有重寫接口方法。例如,如果我們將@Override 注釋添加到 isNull()方法中,將導(dǎo)致編譯器錯誤。
現(xiàn)在,當(dāng)我們運行應(yīng)用程序時,會得到以下輸出。

Interface Null Check
Impl Null Check

如果我們將接口方法從 static 設(shè)置為 default,我們將得到以下輸出。

Impl Null Check
MyData Print::
Impl Null Check

Java 接口靜態(tài)方法僅對接口方法可見,如果我們從 MyDataImpl 類中移除 isNull()方法,我們將無法將其用于 MyDataImpl 對象。但是和其他靜態(tài)方法一樣,我們可以使用類名來使用接口靜態(tài)方法。例如,有效語句將是:

boolean result = MyData.isNull("abc");

java 接口靜態(tài)方法要點:

  1. Java 接口靜態(tài)方法是接口的一部分,不能用于實現(xiàn)類對象。
  2. Java 接口靜態(tài)方法適合于提供實用方法,例如空檢查、集合排序等。
  3. Java 接口靜態(tài)方法通過不允許實現(xiàn)類重寫它們來幫助我們提供安全性。
  4. 我們不能為 Object 類方法定義接口靜態(tài)方法,我們將得到編譯器錯誤為“這個靜態(tài)方法不能從 Object 中隱藏實例方法”。這是因為在 java 中不允許這樣做,因為 Object 是所有類的基類,我們不能有一個類級靜態(tài)方法和另一個具有相同簽名的實例方法。
  5. 我們可以使用 java 接口靜態(tài)方法來移除諸如集合之類的實用工具類,并將其所有靜態(tài)方法移動到相應(yīng)的接口,這樣就很容易找到和使用。

Java 函數(shù)式接口

在結(jié)束本文之前,我想簡單介紹一下功能接口。只有一個抽象方法的接口稱為函數(shù)式接口。

引入了一個新的注釋@functionainterface 來將接口標(biāo)記為 Functional 接口。@functionainterface 注釋是一種避免在功能接口中意外添加抽象方法的工具。這是可選的,但使用它是很好的實踐。

Java 8 的功能性接口是人們期待已久且備受關(guān)注的特性,因為它使我們能夠使用 lambda 表達(dá)式來實例化它們。添加了一個新的包 java.util.function 和一堆函數(shù)接口,為 lambda 表達(dá)式和方法引用提供目標(biāo)類型。我們將在以后的文章中研究函數(shù)接口和 lambda 表達(dá)式。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一:java概述:1,JDK:Java Development Kit,java的開發(fā)和運行環(huán)境,java的開發(fā)工...
    ZaneInTheSun閱讀 2,823評論 0 11
  • 一、基礎(chǔ)知識:1、JVM、JRE和JDK的區(qū)別:JVM(Java Virtual Machine):java虛擬機...
    殺小賊閱讀 2,576評論 0 4
  • 面向?qū)ο笾饕槍γ嫦蜻^程。 面向過程的基本單元是函數(shù)。 什么是對象:EVERYTHING IS OBJECT(萬物...
    sinpi閱讀 1,228評論 0 4
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對...
    cosWriter閱讀 11,688評論 1 32
  • 第十八章 門開 權(quán)新禹低著頭,看著這條只有五個字的短信。四周很寂靜,來來往往的人走過他的身邊。 權(quán)新禹抬起頭來,看...
    寶弓閱讀 174評論 0 0

友情鏈接更多精彩內(nèi)容