30分鍾入門Java8之默認方法和靜態接口方法


30分鍾入門Java8之默認方法和靜態接口方法

前言

上一篇文章30分鍾入門Java8之lambda表達式,我們學習了lambda表達式。現在繼續Java8新語言特性的學習,今天,我們要學習的是默認方法和靜態接口方法。

這一Java8的新語言特性,在Android N中也得到了支持。至於如何在Android開發中配置Java8的開發環境,請查看上一篇文章30分鍾入門Java8之lambda表達式

默認方法

默認方法讓我們能給我們的軟件庫的接口增加新的方法,並且能保證對使用這個接口的老版本代碼的兼容性

下面通過一個簡單的例子來深入理解下默認方法:

  • 1.一天,PM說我們的產品需要獲取時間和日期。於是我們就寫了一個設置和獲取日期時間的接口類TimeClient
public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
                        int hour, int minute, int second);
    LocalDateTime getLocalDateTime();
}

以及這個接口的實現類SimpleTimeClient:

public class SimpleTimeClient implements TimeClient {

    private LocalDateTime localDateTime;

    public SimpleTimeClient(){
        localDateTime = LocalDateTime.now();
    }

    @Override
    public void setTime(int hour, int minute, int second) {
        LocalTime localTime = LocalTime.of(hour, minute, second);
        LocalDate localDate = LocalDate.from(localDateTime);
        localDateTime = LocalDateTime.of(localDate,localTime);
    }

    @Override
    public void setDate(int day, int month, int year) {
        LocalDate localDate = LocalDate.of(day, month, year);
        LocalTime localTime = LocalTime.from(localDateTime);
        localDateTime = LocalDateTime.of(localDate, localTime);
    }

    @Override
    public void setDateAndTime(int day, int month, int year, int hour, int minute, int second) {
        LocalDate localDate = LocalDate.of(day, month, year);
        LocalTime localTime = LocalTime.of(hour, minute, second);
        localDateTime = LocalDateTime.of(localDate, localTime);
    }

    @Override
    public LocalDateTime getLocalDateTime() {
        return localDateTime;
    }

    @Override
    public String toString() {
        return localDateTime.toString();
    }

    public static void main(String[] args) {
        TimeClient timeClient = new SimpleTimeClient();
        System.out.println(timeClient.toString());
    }
}

2.可是PM說我們這個產品吶,不光國內用,各種其他時區的顧客也會使用。於是給你增加了新的需求:獲取指定時區的日期和時間

以往我們都會這么做:

重寫接口,增加方法

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
        int hour, int minute, int second);
    LocalDateTime getLocalDateTime(); 
    //新增的方法                          
    ZonedDateTime getZonedDateTime(String zoneString);
}

這樣我們的實現類也要相應的進行重寫。

public class SimpleTimeClient implements TimeClient {

    private LocalDateTime localDateTime;
    ...
    ZonedDateTime getZonedDateTime(String zoneString){
       return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
    
     static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }
    
 }

這樣寫會導致我們要去重寫每個實現了TimeClient接口的類。而這大大增加了我們的實現需求的負擔。

正是為了解決Java接口中只能定義抽象方法的問題。Java8新增加了默認方法的特性。下面讓我們來使用默認方法實現需求。

public interface TimeClient {
    void setTime(int hour, int minute, int second);
    void setDate(int day, int month, int year);
    void setDateAndTime(int day, int month, int year,
        int hour, int minute, int second);
    LocalDateTime getLocalDateTime();                          
     static ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }
    //默認方法 
    default ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }
}

默認方法關鍵字為default,以往我們只能在接口中定義只有聲明沒有實現的方法。有了默認方法,我們就能編寫完整的方法。

這樣我們就不需要修改繼承接口的實現類,就給接口添加了新的方法實現。

public static void main(String[] args) {
        TimeClient timeClient = new SimpleTimeClient();
        System.out.println(timeClient.toString());
        System.out.println(timeClient.getZonedDateTime("test"));
    }

繼承含有默認方法的接口

當我們繼承含有默認方法的接口時,一般有以下三種情況

  • 不去管默認方法,繼承的接口直接繼承默認方法
//1.不去管默認方法

public interface AnotherTimeClient  extends  TimeClient{
}

通過下面的測試代碼,我們知道AnotherTimeClient接口直接繼承了TimeClient接口的默認方法getZonedDateTime

 Method[] declaredMethods = AnotherTimeClient.class.getMethods();
        for(Method method:declaredMethods){
            System.out.println(method.toString());
        }
 
//output:
//public default java.time.ZonedDateTime xyz.johntsai.lambdademo.TimeClient.getZonedDateTime(java.lang.String)
  • 重新聲明默認方法,這樣會使得這個方法變成抽象方法
//重新聲明默認方法,使之變為抽象方法
public interface AbstractZoneTimeClient extends TimeClient{
    @Override
    ZonedDateTime getZonedDateTime(String zoneString);
}


測試可以發現getZonedDateTime 方法由默認方法變為了抽象方法:

Method[] methods = AbstractZoneTimeClient.class.getMethods();
        for(Method method:methods){
            System.out.println(method.toString());
        }
//output:       
//public abstract java.time.ZonedDateTime xyz.johntsai.lambdademo.AbstractZoneTimeClient.getZonedDateTime(java.lang.String)
        
  • 重新定義默認方法,這樣會使得方法被重寫
//3.重新定義默認方法
public interface HandleInvalidZoneTimeClient extends TimeClient {
    default ZonedDateTime getZonedDateTime(String zoneString){
        try {
            return ZonedDateTime.of(getLocalDateTime(), ZoneId.of(zoneString));
        } catch (DateTimeException e) {
            System.err.println("Invalid zone ID: " + zoneString +
                    "; using the default time zone instead.");
            return ZonedDateTime.of(getLocalDateTime(),ZoneId.systemDefault());
        }
    }
}

實現HandleInvalidZoneTimeClient 接口的類將擁有重寫過的getZonedDateTime 方法。

靜態方法

在Java8的接口中,我們不光能寫默認方法,還能寫靜態方法。上面的例子中正好用到了靜態方法。

public interface TimeClient {
    // ...
    static public ZoneId getZoneId (String zoneString) {
        try {
            return ZoneId.of(zoneString);
        } catch (DateTimeException e) {
            System.err.println("Invalid time zone: " + zoneString +
                "; using default time zone instead.");
            return ZoneId.systemDefault();
        }
    }

    default public ZonedDateTime getZonedDateTime(String zoneString) {
        return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
    }    
}


免責聲明!

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



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