默认方法和抽象方法的区别在于:抽象方法是必须要实现的,而默认方法不是。相反,每个接口必须提供一个所谓的默认方法实现,所有的实现类都会默认继承得到这个方法(如果需要也可以重写这个默认实现)。我们来看看下面这个例子:
01 | private interface Defaulable { |
03 | default String notRequired() { |
04 | return "Default implementation" ; |
07 | private static class DefaultableImpl implements Defaulable {} |
08 | private static class OverridableImpl implements Defaulable { |
10 | public String notRequired() { |
11 | return "Overridden implementation" ; |
接口Defaulable在定义中使用关键字default声明了一个默认方法notRequired()。有一个类DefaultableImpl实现了这个接口,它没有对默认方法做任何更改。另一个类OverridableImpl,则重写了接口中的默认实现,实现了自己的逻辑。
Java 8提供的另一个很有意思的特性是接口可以声明静态方法(同时提供实现)。举个例子:
1 | private interface DefaulableFactory { |
3 | static Defaulable create( Supplier< Defaulable > supplier ) { |
下面这段代码将之前例子中提到的默认方法和静态方法放在了一起:
1 | public static void main( String[] args ) { |
2 | Defaulable defaulable = DefaulableFactory.create( DefaultableImpl:: new ); |
3 | System.out.println( defaulable.notRequired() ); |
4 | defaulable = DefaulableFactory.create( OverridableImpl:: new ); |
5 | System.out.println( defaulable.notRequired() ); |
这个程序的控制台输出如下:
1 | Default implementationOverridden implementation |
JVM中默认方法的实现非常高效,而且方法调用的字节码指令支持默认方法。默认方法使得已有的Java接口能够改进而不会导致编译过程失败。接口java.util.Collection中新增了大量的方法,都是很好的示例,如: stream(), parallelStream(),forEach(), removeIf(),等等。
虽然默认方法很强大,我们还是要谨慎使用它:在将一个方法定义为default方法之前,最好三思是不是必须要这么做,因为它可能在层级复杂的情况下引起歧义和编译错误。