1.6 接口中的静态方法

问题

用户希望为接口添加一个类级别(class level)的工具方法和相应的实现。

方案

将接口方法声明为 static,并以常规方式添加实现。

讨论

Java 类的静态成员是类级别的。换言之,静态成员与整个类相关联,而不是与特定的实例相关联。但从设计的角度看,静态成员在接口中的使用是有问题的,举例如下。

  • 当多个不同的类实现接口时,类级别成员指的是什么?
  • 类是否需要通过实现接口来使用静态方法?
  • 类中的静态方法是通过类名访问的。如果类实现了一个接口,那么静态方法是通过类名还是接口名来调用呢?

为解决这些问题,Java 开发团队尝试了几种不同的方案。

在 Java 8 之前,接口完全不支持使用静态成员,不过这导致了工具类的产生,这是一种只包含静态方法的类。java.util.Collections 就是一种典型的工具类,它不仅包括用于排序和搜索的方法,也定义了采用同步或不可修改的类型包装集合的方法。在 NIO 包中,另一种工具类是 java.nio.file.Paths,它只包括从字符串或 URI 中解析 Path 实例的两个静态方法。

而在 Java 8 中,我们可以随时为接口添加静态方法,步骤如下。

  • 为方法添加 static 关键字。
  • 提供一种无法被重写的实现。此时,静态方法类似于默认方法,包含在 Javadoc 的 Default Methods(默认标签)中。
  • 通过接口名访问方法。类不需要通过实现接口来使用静态方法。

java.util.Comparator 接口定义的 comparing 方法就是一种实用的静态方法,它包括 comparingIntcomparingLongcomparingDouble 等三种基本变体。此外,Comparator 接口还包括 naturalOrderreverseOrder 两种静态方法。例 1-28 给出了这些方法的用法。

例 1-28 字符串排序

  1. List<String> bonds = Arrays.asList("Connery", "Lazenby", "Moore",
  2. "Dalton", "Brosnan", "Craig");
  3. List<String> sorted = bonds.stream()
  4. .sorted(Comparator.naturalOrder())
  5. .collect(Collectors.toList());
  6. // [Brosnan, Connery, Craig, Dalton, Lazenby, Moore]
  7. sorted = bonds.stream()
  8. .sorted(Comparator.reverseOrder())
  9. .collect(Collectors.toList());
  10. // [Moore, Lazenby, Dalton, Craig, Connery, Brosnan]
  11. sorted = bonds.stream()
  12. .sorted(Comparator.comparing(String::toLowerCase))
  13. .collect(Collectors.toList());
  14. // [Brosnan, Connery, Craig, Dalton, Lazenby, Moore]
  15. sorted = bonds.stream()
  16. .sorted(Comparator.comparingInt(String::length))
  17. .collect(Collectors.toList());
  18. // [Moore, Craig, Dalton, Connery, Lazenby, Brosnan]
  19. sorted = bonds.stream()
  20. .sorted(Comparator.comparingInt(String::length)
  21. .thenComparing(Comparator.naturalOrder()))
  22. .collect(Collectors.toList());
  23. // [Craig, Moore, Dalton, Brosnan, Connery, Lazenby]

❶ 自然顺序(字典序)

❷ 反向顺序(字典序)

❸ 按小写名称排序

❹ 按姓名长度排序

❺ 按姓名长度排序,如果长度相同则按字典序排序

本例显示了如何利用 Comparator 接口提供的静态方法对一份演员名单进行排序,名单中出现的演员是这些年来詹姆斯 • 邦德的扮演者。9 有关比较器的详细讨论,请参见范例 4.1。

9我差点将伊德瑞斯 • 艾尔巴(Idris Elba)加入名单,但总算忍住没这么做。(艾尔巴是英国影星,因在《环太平洋》《雷神》等影片中饰演的角色为影迷所熟知,2014 年曾传出他将出演下一任邦德的消息——译者注。)

由于接口中有静态方法,我们不必创建单独的工具类。但需要的话,仍然可以创建工具类。

请注意以下几点:

  • 静态方法必须有一个实现
  • 无法重写静态方法
  • 通过接口名调用静态方法
  • 无须实现接口以使用静态方法

另见

接口中静态方法的应用贯穿全书,有关 Comparator 接口定义的静态方法请参见范例 4.1。