为什么实用默认方法?场景如下
本章节:描述了一个例子,涉及计算机控制汽车的制造商,他们发布行业标准接口,描述哪些方法可以被调用来操作他们的汽车。如果这些电脑控制的汽车制造商将新的功能(如飞行)添加到他们的汽车怎么办?
这些制造商将需要指定新的方法,使其他公司(如电子指导仪器制造商)能够使其软件适应飞行汽车。这些汽车制造商会在哪里申报这些新的与飞行有关的方法?
如果将它们添加到原始接口,那么实现这些接口的程序员将不得不重写其实现。如果他们将它们添加为静态方法,那么程序员将它们视为实用方法,而不是基本的核心方法。
默认方法使您能够向库的接口添加新功能,并确保与旧版本的这些接口编写的代码的二进制兼容性。
考虑以下接口,TimeClient:
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对象(除了存储时区信息之外的类似于LocalDateTime对象)指定时区的功能:
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关键字的默认方法。接口中的所有方法声明(包括默认方法)都是隐式公开的,因此可以省略public修饰符。 使用此接口,您不必修改SimpleTimeClient类,并且此类(以及实现接口TimeClient的任何类)将具有已定义的方法getZonedDateTime。
以下示例TestSimpleTimeClient从SimpleTimeClient的实例调用getZonedDateTime方法:
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());
}
}