Java8新特性 接口默认方法,接口静态方法

官方原文(英文)地址:https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html


Default Methods

Interfaces 章节中举了个例子,汽车生产商制定了操作汽车的接口,那现在如果汽车生产商给汽车添加了新功能(比如起飞)后会怎么样呢?生产商需要制定一个新方法,来让其他公司适配软件让汽车起飞。汽车生产商应该在哪里声明这个方法?如果他们在原始的接口中添加,那所有实现了接口的开发者都需要重新实现这个方法。如果他们添加一个静态方法,那开发者会认为这是个功能性的方法,不是核心方法。

Default methods就是为了解决上述这个问题,能让你在接口中添加新方法并且保证与老版本代码兼容。

请看下面这个接口例子,:

import java.time.*; 
 
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, 实现了 TimeClient接口:

package defaultmethods;

import java.time.*;
import java.lang.*;
import java.util.*;

public class SimpleTimeClient implements TimeClient {
    
    private LocalDateTime dateAndTime;
    
    public SimpleTimeClient() {
        dateAndTime = LocalDateTime.now();
    }
    
    public void setTime(int hour, int minute, int second) {
        LocalDate currentDate = LocalDate.from(dateAndTime);
        LocalTime timeToSet = LocalTime.of(hour, minute, second);
        dateAndTime = LocalDateTime.of(currentDate, timeToSet);
    }
    
    public void setDate(int day, int month, int year) {
        LocalDate dateToSet = LocalDate.of(day, month, year);
        LocalTime currentTime = LocalTime.from(dateAndTime);
        dateAndTime = LocalDateTime.of(dateToSet, currentTime);
    }
    
    public void setDateAndTime(int day, int month, int year,
                               int hour, int minute, int second) {
        LocalDate dateToSet = LocalDate.of(day, month, year);
        LocalTime timeToSet = LocalTime.of(hour, minute, second); 
        dateAndTime = LocalDateTime.of(dateToSet, timeToSet);
    }
    
    public LocalDateTime getLocalDateTime() {
        return dateAndTime;
    }
    
    public String toString() {
        return dateAndTime.toString();
    }
    
    public static void main(String... args) {
        TimeClient myTimeClient = new SimpleTimeClient();
        System.out.println(myTimeClient.toString());
    }
}

假设你现在想要在TimeClient 接口中添加一个新方法 ZonedDateTime getZonedDateTime(String zoneString):

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

根据TimeClient 接口中的修改,我们必须同样要去修改SimpleTimeClient,并且实现getZonedDateTime方法。然而,与其让getZonedDateTime 声明为抽象方法,不如声明为一个有默认实现的方法。

package defaultmethods;
 
import java.time.*;

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 这个关键字来声明这是个default method。(接口中的所有方法包括默认方法都是public的,所以你可以省略public修饰符)

使用这个接口,你不用修改SimpleTimeClient类,这个类(包括所有实现了TimeClient的类)就有了SimpleTimeClient方法:

package defaultmethods;
 
import java.time.*;
import java.lang.*;
import java.util.*;

public class TestSimpleTimeClient {
    public static void main(String... args) {
        TimeClient myTimeClient = new SimpleTimeClient();
        System.out.println("Current time: " + myTimeClient.toString());
        System.out.println("Time in California: " +
            myTimeClient.getZonedDateTime("Blah blah").toString());
    }
}


当你继承了一个包含默认方法的接口时,你能做这些:

  • 默认继承了这个默认方法.
  • 重新声明这个方法,让它变成抽象方法.
  • 重载这个方法override.

假设你按如下形式继承了这个接口TimeClient :

public interface AnotherTimeClient extends TimeClient { }

任何实现了AnotherTimeClient 接口的类会拥有TimeClient.getZonedDateTime的默认实现。

假设你按如下形式继承了这个接口TimeClient :

public interface AbstractZoneTimeClient extends TimeClient {
    public ZonedDateTime getZonedDateTime(String zoneString);
}

任何实现了AnotherTimeClient 接口的类必须实现getZonedDateTime方法;(这个方法变成抽象方法了)

假设你按如下形式继承了这个接口TimeClient :

public interface HandleInvalidTimeZoneClient extends TimeClient {
    default public 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());
        }
    }
}

重载了


除了默认方法,你还可以在接口中定义静态方法。这让你更简单地在代码包中添加方法;你可以直接在接口类中添加静态方法,而不用另外分离一个类来添加这个静态方法。例如:

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

跟普通类中的静态方法一样,用关键字static来表明方法是静态方法。接口中的所有方法都是public,所以你可以省略public修饰符。


默认方法能让你在已有的接口上新增方法并且不影响老版本使用这个接口的代码。特别的,默认方法能让你在已有的接口上新增能接受lambda表达式参数的方法。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值