java8引入了stream。支持集合对象转化成为stream。集合的接口上增加了一个方法。
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
我们可以看到集合的接口上。增加了一个实现。
这个就是java8带来的一个特性。接口支持了default关键字。
这样带来了什么好处呢?
default的好处
我们尝试如果没有default,我们要如何实现。
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
这个是arraylist的实现。我们看到如果想给所有的核心类库加。似乎我们只要collection加上接口。然后再AbstractList实现就可以了,这样核心类库的list就可以了。同理还有map
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable {
如果是第三方的实现呢,例如自己为了区别,直接实现了List或者直接实现了collection。这样的代码最可怕了,需要我们一个一个加上方法,才能编译过去,而且实现的内容大同小异。
第三方实现的时候,可能没有核心类库这么强大,没有做中间的抽象类做区分,实现起来可能就极其复杂。
最麻烦的是,原来6写出来的代码,编译出的class文件无法直接跑在8上。严重影响升级版本的。
直接在接口上加一个实现,直接避免了这个问题,用户的code基本是不要改变的。
default的坏处
上面从兼容性,开发等角度,讲了default如果没有的话,可能带来的问题。
在8之前,接口和抽象类是有明确的分工的。
- 接口是用来定义规范。
- 抽象类是用来复用代码。
根据这样的设计规则,我们设计code会更有章法。抽象类一出,大家的关注点都在protected方法和final方法。这个一般意味着,重点聚焦在继承和抽象层面的规范化。
按照这个角度,看stream方法应该是设计在抽象类上的。并且设计成final。spliterator是一个protected方法,希望子类继承的时候,各自做各自的实现。
在接口中可以加方法实现,这个会导致原来的潜在约定失效。大家得仔细想想这个实现具体来自哪里。
所以我们正常开发依旧会遵循接口和抽象类的区别,但是在改造系统上,我们会利用default关键字来让改造更快。
菱形继承问题
这个多层继承本来是cpp的多继承问题,现在java的接口也同时有了这个问题。原来的接口是没有实现的。所以最终只有一份实现。但是现在不一样了。
interface FA {
default void say() {
System.out.println("FA");
}
;
}
interface FA1 extends FA{
}
这种继承是没有问题的。
interface FA {
default void say() {
System.out.println("FA");
}
;
}
interface FB {
default void say() {
System.out.println("FB");
}
}
interface FC extends FA, FB {
@Override
default void say() {
}
}
这种情况,编译器会要求你FC实现方法。
interface FA {
default void say() {
System.out.println("FA");
}
}
inerface FB {
default void say() {
System.out.println("FB");
}
}
interface FC extends FA, FB {
@Override
default void say() {
FB.super.say();
}
}
可以再实现中,主动的指定实现的到底是来自谁的方法。
这里建议多层和菱形的情况下,虽然有默认规则,但还是最好手动指定一下实现的情况。因为默认的情况,依赖继承顺序。如果有一个稍加改动,默认的值就变了。但是编译时还发现不了。所以最好都是明确指定,之后就不可动了,后面谁修改的时候,需要手动确认一次。
共同学习,写下你的评论
评论加载中...
作者其他优质文章