简介:本文通过分析对JDK中对默认方法 (default method) 的应用,浅析默认方法的作用,以及对我们接口设计的一些启发。

Default methods enable new functionality to be added to the interfaces of libraries and ensure binary compatibility with code written for older versions of those interfaces.

默认方法允许您添加新的功能到现有库的接口中,并能确保与采用旧版本接口编写的代码的二进制兼容性。

什么是默认方法

  • 接口本身只能进行方法的定义,默认方法就是接口方法的“默认实现”。接口方法前加上关键字default即可。

为什么要有默认方法

在 Java 8 之前,接口与其实现类之间的耦合度太高(tightly coupled),当需要为一个接口添加方法时,所有的实现类都必须随之修改。默认方法解决了这个问题,它可以为接口添加新的方法,而不会破坏已有的接口的实现。这在 lambda 表达式作为 Java 8 语言的重要特性而出现之际,为升级旧接口且保持向后兼容(backward compatibility)提供了途径。同时,默认方法的加入,也能改变传统Java接口的设计思想(Java 被人诟病的 Interface -> Abstract -> Class 模式),简化接口设计。

Java 8中 Iterable 接口中的 forEach 方法:

 default void forEach(Consumer<? super T> var1) {
        Objects.requireNonNull(var1);
        Iterator var2 = this.iterator();

        while(var2.hasNext()) {
            Object var3 = var2.next();
            var1.accept(var3);
        }
    }

Java传统接口设计模式

Java 8之前,接口只能作为声明但不能提供任何实现。因此,为了添加一些实现,我们都需要一个 Abstract 类,如下图:

  • 接口层定义相关方法
  • Abstract 类实现公共方法
  • 如果子类需要自己需要自己的行为则直接重写(Override)即可。

问题产生

在大部分的情况下,这种设计都是没有问题的,但是还是比较繁琐,下面是 Java Collections API List部分的继承关系:

我们以 List 接口中的 sort() 方法来分析。只有类,即 AbstractListMyList 才能实际实现此方法,而具体实现是完全一致的,这就需要我们复制代码了。有人说,为什么不直接继承 AbstractList ,我们都知道Java中是不允许多继承的,有些情况会让你不得不这么做。

其次,如果我们给需要给 List 添加一个新的方法,那么就不得不对所有 List 的 实现类都添加此方法的实现,这是最糟糕的操作了。

Java API的设计者非常清楚这个问题,因此将 sort() 方法移到了一个只有静态方法的无关类中,没错,就是 Collections ,这样虽然解决了问题,但是却偏离的Java面向对象的思想。

Java 7中 Collections.sort(List<T> list) 方法实现如下:

  public static <T extends Comparable<? super T>> void sort(List<T> list) {
        Object[] a = list.toArray();
        Arrays.sort(a);
        ListIterator<T> i = list.listIterator();
        for (int j=0; j<a.length; j++) {
            i.next();
            i.set((T)a[j]);
        }
    }

Default Method 改善

Java8 引入Default Method后,很大程度上可以减少 Abstract 类的依赖,也能更好的实现“面向对象”,毕竟排序应当属于 List 本身的行为。

Java 8中 Collectionssort() 方法还给 List
Collections.sort(List<T> list) 方法实现如下:

	public static <T extends Comparable<? super T>> void sort(List<T> list) {
	    list.sort(null);
	}

List 接口中的 sort() 方法如下:

	default void sort(Comparator<? super E> c) {
	    Object[] a = this.toArray();
	    Arrays.sort(a, (Comparator) c);
	    ListIterator<E> i = this.listIterator();
	    for (Object e : a) {
	        i.next();
	        i.set((E) e);
	    }
	}

同时 default method 的引入给接口的扩展带来了极大的便利,我们可以随意扩展新的方法而不必过于考虑以前的实现。

参考资料:

Q.E.D.