聊聊Java8接口中的default和static方法

JDK1.8之前的接口回顧

      在jdk1.8之前,我們對接口的認知是這樣的:

     1、方法:只能包含public和abstract的方法,即使定義爲:

interface Shape {
   //獲取幾何圖形的面積
   Double getArea(double length, double width);
}

 方法前面也默認加了public abstract修飾

    2、字段:只能包含常量,即public static final 修飾的變量

interface Shape {
   int length = 0;
}

即使這樣寫,也是默認加上了public static final修飾。

遇到的問題

     現在我們有很多類實現了該接口,有三角形trangle,有圓形circle······

class Trangle implements Shape {

    @Override
    public Double getArea(double length, double width) {
        return length * width / 2;
    }
}

class Circle implements Shape {

    @Override
    public Double getArea(double length, double width) {
        //調用方法時默認length傳半徑
        return 3.14 * length * length;
    }
}

    有一天,我們發現接口功能不夠用了,需要增加一個計算周長的方法

    這時候,JDK1.7及其之前版本該怎麼辦呢?

  • 管他三七二十一,往接口裏直接加個方法,強迫所有實現該幾何圖形的接口的實現類(正方形、圓形、三角形······)都實現最新的接口方法
  • 把接口代碼移到抽象類,添加一個有默認實現的計算周長的方法,但是所有實現類都要改爲繼承,遇到實現類繼承別的父類就行不通了(java只有單繼承)
  • 添加一個新接口,新接口裏加上一個計算周長的方法,讓所有實現了Shape接口的類再實現新的接口,看起來很美好,接口本身也是這麼使用的,但是如果這個方法讓所有的實現類再實現一遍,還是挺麻煩的。

新的選擇——默認方法

     JDK1.8針對這種接口不易擴展的現象,在接口新增default方法,可以有效解決上述遇到的接口拓展新方法的問題。原先的實現類不用改任何代碼就擁有了新的能力,有點像從接口繼承了一個有實現的方法,可以直接調用。

     具體實現:

package com.changan.eurekademo.onepointeight;


public class DefaultMethodTest {
    public static void main(String[] args) {
        System.out.println(new Circle().getPerimeterOfCircle(3));
    }
}

interface Shape {
    int a = 0;

    public Double getArea(double length, double width);

    /**
     * 新增默認方法,爲四邊形擴展計算周長
     *
     * @param length 長
     * @param width  款
     * @return java.lang.Double
     */
    default Double getPerimeterOfQuadrilateral(double length, double width) {
        return (length + width) * 2;
    }

    /**
     * 新增默認方法,爲圓形計算周長
     *
     * @param redius 半徑
     * @return java.lang.Double
     */
    default Double getPerimeterOfCircle(double redius) {
        return 3.14 * 2 * redius;
    }

}

class Trangle implements Shape {

    @Override
    public Double getArea(double length, double width) {
        return length * width / 2;
    }
}

class Circle implements Shape {

    @Override
    public Double getArea(double length, double width) {
        //調用方法時默認length傳半徑
        return 3.14 * length * length;
    }
}

可以看到輸出結果是:

靜態方法

      靜態方法比較直觀,類比普通類的靜態方法,就是可以不實例化,直接用類名調用的方法,接口的靜態方法也是一樣,直接用接口名調用方法。

public class DefaultMethodTest {
    public static void main(String[] args) {
        System.out.println(new Circle().getPerimeterOfCircle(3));
        System.out.println("-------------------------------------------");
        System.out.println(Shape.describe());
    }
}

interface Shape {
    int a = 0;

    public Double getArea(double length, double width);

    /**
     * 新增默認方法,爲四邊形擴展計算周長
     *
     * @param length 長
     * @param width  款
     * @return java.lang.Double
     */
    default Double getPerimeterOfQuadrilateral(double length, double width) {
        return (length + width) * 2;
    }

    /**
     * 新增默認方法,爲圓形計算周長
     *
     * @param redius 半徑
     * @return java.lang.Double
     */
    default Double getPerimeterOfCircle(double redius) {
        return 3.14 * 2 * redius;
    }

    /**
     * 接口描述方法,描述接口用途及其他信息
     *
     * @return java.lang.String
     */
    static String describe() {
        return "我是一個幾何圖形接口";
    }

}

class Trangle implements Shape {

    @Override
    public Double getArea(double length, double width) {
        return length * width / 2;
    }
}

class Circle implements Shape {

    @Override
    public Double getArea(double length, double width) {
        //調用方法時默認length傳半徑
        return 3.14 * length * length;
    }
}

      可以驚奇地看到,用接口直接調了一個方法,這個現象可以類比匿名類。

      比如JDK1.7,我們要實現一個接口有一個方法,並且不用實例化的類來調用應該這麼做:

public class DefaultMethodTest {
    public static void main(String[] args) {
        System.out.println(new Shape() {
            @Override
            public Double getArea(double length, double width) {
                return null;
            }

            @Override
            public String describe() {
                return "我是一個幾何圖形接口";
            }
        }.describe());
    }
}

interface Shape {
    int a = 0;

    Double getArea(double length, double width);

    String describe();

}

 

     但是這樣做完全沒有太大的意義,沒有接口中定義靜態方法來的優雅、簡單。

抽象類VS接口靜態/默認方法

       帶默認或者靜態方法的接口像是一個抽象類嗎?的確有點像,但是抽象類可能包含可變狀態(實例變量),而接口只能定義行爲和常量。另外,一個類只能直接從一個類繼承,但可以實現所需的任意數量的接口。所以,如果需要可變狀態,並且確定某個類將構成一個合理的子類,則需要考慮一個抽象類。在其他情況下,使用具有默認/靜態方法的接口就好了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章