Java8实战之默认方法
前言
在前面,我们学习了Lambda以及Stream,也体会到了这两者结合后所带来的方便性,尤其是Stream,有了Stream之后,对于容器的大部分操作都变得非常简单,只需要通过组合一系列的中间操作以及结束操作,就能筛选,转换,收集需要的对象,然而,这中间有一个问题,那就是似乎大部分的容器都支持stream()
这个方法,难道是所有的实现都进行了修改了吗?这肯定是不可能,一方面,修改现有的容器,为每个容器加入一个方法,是非常繁琐的操作;另一方面,如果我们想实现自己的容器,还要自己实现对应的stream()
方法?。但除了给每个子类加入方法,那就只能是在接口中加入,但在接口中加入,又似乎不合理,因为所有的实现类都必须实现该方法了,答案就在默认方法中。
默认方法
为了解决上面的矛盾,在Java8中加入了新的机制,默认方法,默认方法用关键字default
来标注,被default
所标注的方法,需要提供实现,而子类可以选择实现或者不实现该方法,通过这样的机制,就能够实现在接口中加入新方法,则子类无需进行任何改动,需要注意的是default
只能用于接口中修饰方法,不能在类中使用
interface DefaultMethodTest { default void print() { System.out.println("hello"); } }
我们来看下容器中的stream
方法的是否如此
default Stream<E> stream() { return StreamSupport.stream(spliterator(), false); }
关于StreamSupport
这里就不展开了,等以后继续深入学习之后,再来研究它,主要是现在还没搞懂,囧。不过,通过JDK源码,我们确实看到了default stream()
方法
不过看到这里,可能又会有一个疑惑,Java中通过单继承机制来避免多继承所带来的各种问题,比如菱形继承问题,而在接口中引入默认实现,同时接口又支持多重实现,那么就会出现两个接口中有同样的方法,那这样子该怎么处理呢?
interface A { default void print() { System.out.println("interface A"); } }interface B { default void print() { System.out.println("interface B"); } }// 出现混乱class C implements A, B { }
Java8中采用了强制的手段,其规则如下
如果是继承一个类并且实现接口,两者具有相同的默认方法,以类为基准
如果是继承或者实现一个已经继承的接口,以子接口中的默认方法为准
如果此时依旧出现混乱,则必须显示进行处理(显示实现)
从上面的规则可以看到,其实就是以类为优先,如果是父类已经包含了默认方法,则以父类的为基准,如下
class D implements A { @Override public void print() { System.out.println("class A"); } }class C extends D implements A { public static void main(String[] args) { new C().print(); // 输出 class A } }
interface D extends A { @Override default void print() { System.out.println("interface D"); } }class C implements D, A { public static void main(String[] args) { new C().print(); // 输出 interface D } }
可以看到上面的情况是具有明显的继承形式的,并且是能够明显地区分出哪一个是最接近目标类的,所以就以该类中的实现为准
当无法明显地进行区分的时候,比如下面的例子,就需要强制实现了
class C implements A, B { }
作者:颜洛滨
链接:https://www.jianshu.com/p/3e0ff788004a