Zhenyu’s Blog

陌上发花,可以缓缓醉矣, 忍把浮名,换了浅酌低唱。

Java 8 预览之Default Method

| Comments

打开JDK 8的源代码,你会发现很多接口中多了一些标记为default的方法。在Java的早期版本中,default关键字只在switch语句中使用,在方法上使用代表什么含义呢?让我们一起来看一下Java 8新特性:Default Method

何为Default Method

默认方法(Default Method),又称虚拟扩展方法(Virtual Extension Methods)或保卫者方法(Defender Method),是JSR 335的一部分。让我们先看一下JDK中的实际例子:

public interface Iterable<T> {
    Iterator<T> iterator();

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
}

default关键字标记的forEach方法即是所谓的Default Method,这里有几个有意思的地方:

  • forEach方法虽然定义在接口中,但是却有方法体和实现代码,这在Java 8 之前是无法通过编译的。
  • 即使Iterable接口定义了新方法forEach,其子接口Collection、以及实现这些接口的类(如ArrayList)却没有Override这个方法且无编译错误

为什么需要Default Method

看到了上面关于Default Method的描述,作为API设计者的你可能已经开始欢呼了。即使你的API已经发布出去了,你依然可以为接口添加新方法并且无需考虑向后兼容问题。Java 8引入Default Method也正是基于这个原因 注1

Default Method将带给我们什么

Ruby的创造者松本行弘在《松本行弘的程序世界》中提到 注2

其实继承包含两种含义。一种是“类都有哪些方法”,也就是说这个类都支持些什么操作,即规格的继承。

另外一种是,“类中都用了什么数据结构和什么算法”,也就是实现的继承。

静态语言中,这两者的区别很重要。Java就对这两者有很明确的区分,实现的继承用extends来继承父类,规格的继承用implements来实现接口。

引入Default Method后,Java接口就具有了“实现继承”的能力,从而更像是一种mixin,增加了代码重用的能力,同时也使面向对象设计更加灵活。


  • 注1: 可以想象,Java 8对Lambda的支持必然会影响JDK API中的接口,上面的forEach就是很好的例子,如果直接在接口中添加方法,就会导致所有实现该接口的类或接口无法通过编译,而有了Default Method,一切都变得容易了。
  • 注2: 摘自2.3.9 继承的两种含义

Comments