Java 8新特性(1) 函数式接口与默认方法
JDK8 下载:https://jdk8.java.net/download.html
函数式接口简介
在 Java 中,Marker(标记)类型的接口是一种没有方法或属性声明的接口,简单地说,marker 接口是空接口。相似地,函数式接口(functional interface)是只包含一个抽象方法声明的接口。
定义了这种类型的接口,使得以其为参数的方法,可以在调用时,使用一个 lambda 表达式作为参数。从另一个方面说,一旦我们调用某方法,可以传入 lambda 表达式作为参数,则这个方法的参数类型,必定是一个函数式的接口。
JDK8 提供 @FunctionalInterface
作为注解,这个注解是非必须的,只要接口符合函数式接口的标准(即只包含一个方法的接口)。
函数式接口中,只能有一个函数需要被实现,但是也可以有如下例外:
- 默认方法与静态方法并不影响函数式接口的契约,可以任意使用,即:
- 函数式接口中可以有静态方法(JDK8 接口可以有公有的静态方法,JDK9 接口可以有非公有的静态方法)。
- 可以由 default 修饰的默认方法方法,这个关键字是 Java8 中新增的,为的目的就是使得某一些接口,原则上只有一个方法被实现,但是由于历史原因,不得不加入一些方法来兼容整个 JDK 中的 API,所以就需要使用 default 关键字来定义这样的方法
- 可以有 Object 中覆盖的方法,也就是 equals,toString,hashcode 等方法。
JDK 中以前所有的函数式接口都已经使用 @FunctionalInterface
定义,如 java.lang.Runnable 和 java.util.Comparator
默认方法
Default 方法是指,在接口内部包含了一些默认的方法实现(也就是接口中可以包含方法体,这打破了Java 之前版本对接口的语法限制),从而使得接口在进行扩展的时候,不会破坏与接口相关的实现类代码。接下来,让我们看一个例子:
public interface SimpleInterface {
public void doSomeWork();
//使用 default 关键字,创建一个 default 方法,该方法包含了具体的实现代码
default public void doSomeOtherWork(){
System.out.println("DoSomeOtherWork implementation in the interface");
}
}
class SimpleInterfaceImpl implements SimpleInterface{
@Override
public void doSomeWork() {
System.out.println("Do Some Work implementation in the class");
}
/*
* 在 SimpleInterfaceImpl 里,不需要再去实现接口中定义的 doSomeOtherWork 方法
*/
public static void main(String[] args) {
SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
simpObj.doSomeWork();
simpObj.doSomeOtherWork();
}
}/** output:
Do Some Work implementation in the class
DoSomeOtherWork implementation in the interface
*/
实现多个接口
如果一个类实现了两个接口,这两个接口又同时都包含了一个名字相同的 default 方法,并且该类没有实现 default 方法,则会得到一个编译器错误,因为编译器不知道应该在两个同名的 default 方法中选择哪一个,因此产生了二义性。
interface A {
default public void hello(){
System.out.println("A");
}
}
interface B extends A{ // 优先选取最具体的实现
@Override
default public void hello(){
System.out.println("B");
}
}
public class C implements A, B{
public static void main(String[] args) {
C c = new C();
c.hello();
}
// @Override
// public void hello(){ // 类实现的方法,优先级最高
// System.out.println("C");
// }
}/** output:
B
*/
如果想调用 A 的默认函数,则用到新语法 X.super.m(...)
,下面修改 C 类,实现 A 接口,重写一个 hello 方法,如下所示:
public class C implements A{
@Override
public void hello(){
A.super.hello();
}
public static void main(String[] args){
new C().hello();
}
}/** output:
A
*/
默认方法与抽象类的非抽象方法的区别
相同点:
- 都是抽象类型;
- 都可以有实现方法(以前接口不行);
- 都可以不需要实现类或者继承者去实现所有方法,(以前不行,现在接口中默认方法不需要实现者实现)
不同点:
- 抽象类不可以多重继承,接口可以(无论是多重类型继承还是多重行为继承);
- 抽象类和接口所反映出的设计理念不同。其实抽象类表示的是 "is-a" 关系,接口表示的是 "like-a" 关系;
- 接口中定义的变量默认是 public static final 型,且必须给其初值,所以实现类中不能改变其值;抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
- 接口的 default methods 只能是 public。抽象类的 abstract method 可以是 protected。
接口的静态方法
除了抽象方法和默认方法,从 Java8 开始,接口也可以有公有静态方法了。JDK9 接口可以有非公有的静态方法。
参考
https://www.cnblogs.com/ownraul/p/5551545.html
http://www.importnew.com/7302.html
https://my.oschina.net/benhaile/blog/176007
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com
文章标题:Java 8新特性(1) 函数式接口与默认方法
文章字数:1.2k
本文作者:Bin
发布时间:2019-03-13, 21:06:22
最后更新:2019-08-06, 00:07:35
原始链接:http://coolview.github.io/2019/03/13/Java8/Java%208%E6%96%B0%E7%89%B9%E6%80%A7(1)%20%E5%87%BD%E6%95%B0%E5%BC%8F%E6%8E%A5%E5%8F%A3%E4%B8%8E%E9%BB%98%E8%AE%A4%E6%96%B9%E6%B3%95/版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。