Java 8新特性(1) 函数式接口与默认方法

  1. 函数式接口简介
  2. 默认方法
    1. 实现多个接口
    2. 默认方法与抽象类的非抽象方法的区别
  3. 接口的静态方法
  4. 参考

JDK8 下载:https://jdk8.java.net/download.html

函数式接口简介

在 Java 中,Marker(标记)类型的接口是一种没有方法或属性声明的接口,简单地说,marker 接口是空接口。相似地,函数式接口(functional interface)是只包含一个抽象方法声明的接口

定义了这种类型的接口,使得以其为参数的方法,可以在调用时,使用一个 lambda 表达式作为参数。从另一个方面说,一旦我们调用某方法,可以传入 lambda 表达式作为参数,则这个方法的参数类型,必定是一个函数式的接口。

JDK8 提供 @FunctionalInterface 作为注解,这个注解是非必须的,只要接口符合函数式接口的标准(即只包含一个方法的接口)。

函数式接口中,只能有一个函数需要被实现,但是也可以有如下例外:

  1. 默认方法与静态方法并不影响函数式接口的契约,可以任意使用,即:
    • 函数式接口中可以有静态方法(JDK8 接口可以有公有的静态方法,JDK9 接口可以有非公有的静态方法)。
    • 可以由 default 修饰的默认方法方法,这个关键字是 Java8 中新增的,为的目的就是使得某一些接口,原则上只有一个方法被实现,但是由于历史原因,不得不加入一些方法来兼容整个 JDK 中的 API,所以就需要使用 default 关键字来定义这样的方法
  2. 可以有 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
*/

默认方法与抽象类的非抽象方法的区别

相同点:

  1. 都是抽象类型;
  2. 都可以有实现方法(以前接口不行);
  3. 都可以不需要实现类或者继承者去实现所有方法,(以前不行,现在接口中默认方法不需要实现者实现)

不同点:

  1. 抽象类不可以多重继承,接口可以(无论是多重类型继承还是多重行为继承);
  2. 抽象类和接口所反映出的设计理念不同。其实抽象类表示的是 "is-a" 关系,接口表示的是 "like-a" 关系;
  3. 接口中定义的变量默认是 public static final 型,且必须给其初值,所以实现类中不能改变其值;抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
  4. 接口的 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" 转载请保留原文链接及作者。

目录