Java8-接口新的两种方法
java8 版之前,接口只有抽象方法,而在Java 8,为接口新增了两种类型的方法。 第一种是默认方法;第二种是静态方法。
1. 默认方法
默认方法使用了default关键字修饰方法名,实际上接口不包含任何实现的方法,而在Java 8中,可以通过使用default关键字来添加默认的方法实现。 接口的实现类可以直接使用这些默认的方法,同时还可以重写默认的方法,这不是强制性的重写。默认方法使得开发者可以在不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。
这样我们就可以在不破坏原来代码的基础上扩展原有的类库,这听上去绝对很酷。但是从另外一个角度来看,这样做有点丧失接口的意义,使得接口定义和具体实现之间的界限模糊不清。可是好处也很明显,我们可以用一种很优雅的方式让接口变得更灵巧,也避免了代码冗余,同时还可以扩展原有类库。
这是一个例子:
1 |
|
由于JVM上的默认方法的实现在字节码层面提供了支持,因此效率非常高。默认方法允许在不打破现有继承体系的基础上改进接口。该特性在官方库中的应用是:给java.util.Collection接口添加新方法,如stream()、parallelStream()、forEach()和removeIf()等等。
之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的 java 8之前的集合框架没有foreach方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了使接口没有引入与现有的实现不兼容发展
那么问题来了。由于同一个方法可以从不同接口引入,自然而然的会有冲突的现象,那么如果有冲突的情况我们怎么来判断使用哪个方法呢?默认方法判断冲突的规则如下:
一个声明在类里面的方法优先于任何默认方法。
否则,则会优先选取最具体的实现。
1.如果一个类从它的父类继承一个方法,又从它的父接口那里继承一个方法名相同的方法。此时,这个类会继承这个父类的方法,而忽略掉这个父接口的方法。
当一个类通过类继承的方式继承的方法不可用的时候,则一个接口中与这个方法名相同的默认方法就会作为一个备用方法。
2.当一个了实现一个有默认方法的接口时,可以不重写默认方法。但是,如果有两个接口的默认方法相同,而类C由同时implements这两个接口,则类C必须重写默认方法,否则编译错误。
尽管默认方法有这么多好处,但在实际开发中应该谨慎使用:在复杂的继承体系中,默认方法可能引起歧义和编译错误。
2. 静态方法
这种类型的静态方法与类中的静态方法相似,可以在接口中使用static关键字定义静态方法。如果我们要调用接口定义的静态方法,只需使用接口名就可以访问这些静态方法。比如:
1 |
|
3. 接口和抽象类的比较
Java8的这一个功能特性出来后,很多同学都反应了,java 8的接口都有实现方法了,跟抽象类还有什么区别?其实还是有的,请看下表对比:
相同点 | 不同点 |
---|---|
1.都是抽象类型 | 1.抽象类不可以多重继承,接口可以(无论是多重类型继承还是多重行为继承) |
2.都可以有实现方法(以前接口不行) | 2.抽象类和接口所反映出的设计理念不同。其实抽象类表示的是”is-a”关系,接口表示的是”like-a”关系 |
3.都可以不需要实现类或者继承者去实现所有方法,(以前不行,现在接口中默认方法不需要实现者实现) | 3.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值;抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。 |