13.2 概述默认方法

经过前述的介绍,我们已经了解了向已发布的API添加方法,对现存代码实现会造成多大的损害。默认方法是Java 8中引入的一个新特性,希望能借此以兼容的方式改进API。现在,接口包含的方法签名在它的实现类中也可以不提供实现。那么,谁来具体实现这些方法呢?实际上,缺失的方法实现会作为接口的一部分由实现类继承(所以命名为默认实现),而无须由实现类提供。

那么,该如何辨识哪些是默认方法呢?其实非常简单。默认方法由default修饰符修饰,并像类中声明的其他方法一样包含方法体。比如,你可以像下面这样在集合库中定义一个名为Sized的接口,在其中定义一个抽象方法size,以及一个默认方法isEmpty

  1. public interface Sized {
  2. int size();
  3. default boolean isEmpty() { ←---- 默认方法
  4. return size() == 0;
  5. }
  6. }

这样任何一个实现了Sized接口的类都会自动继承isEmpty的实现。因此,向提供了默认实现的接口添加方法就不是源码兼容的。

现在,回顾一下最初的例子,即那个Java画图类库和你的游戏程序。具体来说,为了以兼容的方式改进这个库(即使用该库的用户不需要修改他们实现了Resizable的类),可以使用默认方法,提供setRelativeSize的默认实现:

  1. default void setRelativeSize(int wFactor, int hFactor){
  2. setAbsoluteSize(getWidth() / wFactor, getHeight() / hFactor);
  3. }

由于接口现在可以提供带实现的方法,是否这意味着Java已经在某种程度上实现了多继承?如果实现类也实现了同样的方法,那这时会发生什么情况?默认方法会被覆盖吗?现在暂时无须担心这些,Java 8中已经定义了一些规则和机制来处理这些问题。详细的内容会在13.4节进行介绍。

你可能已经猜到,默认方法在Java 8 API中已经大量地使用了。本章已经介绍过前一章中大量使用的Collection接口的stream方法就是默认方法。List接口的sort方法也是默认方法。第3章介绍的很多函数式接口,比如PredicateFunction以及Comparator也引入了新的默认方法,比如Predicate.and或者Function.andThen(记住,函数式接口只包含一个抽象方法,默认方法是种非抽象方法)。

Java 8中的抽象类和抽象接口

那么抽象类和抽象接口之间的区别是什么呢?它们不是都能包含抽象方法和方法体的实现吗?

首先,一个类只能继承一个抽象类,但是一个类可以实现多个接口。

其次,一个抽象类可以通过实例变量(字段)保存一个通用状态,而接口是不能有实例变量的。

请应用你掌握的默认方法的知识,回答一下测验13.1的问题。

测验13.1:removeIf

这个测验里,假设你是Java语言和API的一个负责人。你收到了关于removeIf方法的很多请求,希望能为ArrayListTreeSetLinkedList以及其他集合类型添加removeIf方法。removeIf方法的功能是删除满足给定谓词的所有元素。你的任务是找到用这个新方法优化Collection API的最佳途径。

答案:改进Collection API破坏性最大的方式是什么?你可以把removeIf的实现直接复制到Collection API的每个实体类中,但这种做法实际是在对Java界的犯罪。还有其他的方式吗?你知道吗,所有的Collection类都实现了一个名为java.util.Collection的接口。太好了,那么可以在这里添加一个方法吗?当然可以!你只需要牢记,默认方法是一种以源码兼容方式向接口内添加实现的方法。这样实现Collction的所有类(包括并不隶属Collection API的用户扩展类)都能使用removeIf的默认实现。removeIf的代码实现如下(它实际就是Java 8 Collection API的实现)。它是Collection接口的一个默认方法:

  1. default boolean removeIf(Predicate<? super E> filter) {
  2. boolean removed = false;
  3. Iterator<E> each = iterator();
  4. while(each.hasNext()) {
  5. if(filter.test(each.next())) {
  6. each.remove();
  7. removed = true;
  8. }
  9. }
  10. return removed;
  11. }