java8-接口的默认方法/静态方法/函数式接口 定义与使用
其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。
接口的默认方法
/*
从java 8开始,接口里允许定义默认方法。
格式:
public default 返回值类型 方法名称(参数列表){
方法体
}
备注:接口当中的默认方法,可以解决接口升级的问题。
*/
public interface MyInterfaceDefault {
//抽象方法
public abstract void methodAbs();
//新添加了一个抽象方法
// public abstract void methodAbs2();
//新添加的方法,改成默认方法
public default void methodDefault(){//public可以省略
System.out.println("这是新添加的默认方法");
}
}
============================================
public class MyInterfaceDefaultA implements MyInterfaceDefault{
@Override
public void methodAbs() {
System.out.println("实现了抽象方法,AAA");
}
}
=========================================================
public class MyInterfaceDefaultB implements MyInterfaceDefault {
@Override
public void methodAbs() {
System.out.println("实现了抽象方法,BBB");
}
@Override
public void methodDefault() {
System.out.println("实现类B覆盖重写了接口的默认方法");
}
}
==================================================/*
1、接口的默认方法,可以通过接口实现类对象,直接调用。
2、接口的默认方法,也可以被接口实现类进行覆盖重写。
*/
public class Demo02Interface {
public static void main(String[] args) {
//创建了实现类对象
MyInterfaceDefaultA a=new MyInterfaceDefaultA();
a.methodAbs();//调用抽象方法,实际运行的是右侧实现类。
//调用默认方法,如果实现类当中没有,会向上找接口的。
a.methodDefault();
System.out.println("=====================");
MyInterfaceDefaultB b=new MyInterfaceDefaultB();
b.methodAbs();
b.methodDefault();
}
}
//运行结果:
//实现了抽象方法,AAA
//这是新添加的默认方法
//=====================
//实现了抽象方法,BBB
//实现类B覆盖重写了接口的默认方法
接口的静态方法
/*
从java 8开始,接口当中允许定义静态方法。
格式:
public static 返回值类型 方法名称(参数列表){
方法体
}
提示:就是将abstract或者default换成static即可,带上方法体。
*/
public interface MyInterfaceStatic {
public static void methodStatic(){//public可以省略
System.out.println("这是接口的静态方法!");
}
}
==========================================
public class MyInterfaceStaticImpl implements MyInterfaceStatic {
}
=========================================
/*
注意事项:不能通过接口实现类的对象来调用接口当中的静态方法。
正确用法:通过接口名称,直接调用其中的静态方法。
格式:
接口名称.静态方法名(参数);
*/
public class Demo03Interface {
public static void main(String[] args) {
//创建了实现类对象
MyInterfaceStaticImpl impl=new MyInterfaceStaticImpl();
//错误写法!!!
// impl.methodStatic();
//直接通过接口名称调用静态方法
MyInterfaceStatic.methodStatic();//这是接口的静态方法!
}
}
函数式接口
@FunctionalInterface 注解
什么是函数式接口(Functional Interface)
其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。
这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。
函数式接口用途
它们主要用在Lambda表达式和方法引用(实际上也可认为是Lambda表达式)上。
如定义了一个函数式接口如下:
@FunctionalInterface
public interface Person {
void sayHello(String msg);
}
那么就可以使用Lambda表达式来表示该接口的一个实现(注:JAVA 8 之前一般是用匿名类实现的):
Person personSay = message -> System.out.println("Hello " + message);
关于@FunctionalInterface注解
Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。
正确的例子:
错误的列子:
@FunctionalInterface标记在接口上,“函数式接口”是指仅仅只包含一个 抽象方法*的接口。
在编译期间检查。
@FunctionalInterface 仅对抽象方法检查。
- 1、该注解只能标记在"有且仅有一个抽象方法"的接口上。
- 2、JDK8接口中的静态方法和默认方法,都不算是抽象方法。
- 3、接口默认继承java.lang.Object,所以如果接口显示声明覆盖了Object中方法,那么 也不算抽象方法。

注:该注解不是必须的,如果一个接口符合"函数式接口"定义,那么加不加该注解都没有影响。加上该注解能够更好地让编译器进行检查。如果编写的不是函数式接口,但是加上了@FunctionInterface,那么编译器会报错。
为什么不能用默认方法来重载equals,hashCode和toString?
接口不能提供对Object类的任何方法的默认实现。从接口里不能提供对equals,hashCode或toString的默认实现。因为若可以会很难确定什么时候该调用接口默认的方法。
如果一个类实现了一个方法,那总是优先于默认的实现的。一旦所有接口的实例都是Object的子类,所有接口实例都已经有对equals/hashCode/toString等方法默认实现。因此,一个在接口上的这些默认方法都是没用的,它也不会被编译。(简单地讲,每一个java类都是Object的子类,也都继承了它类中的equals/hashCode/toString方法,那么在类的接口上包含这些默认方法是没有意义的,它们也从来不会被编译。)
通过@FunctionalInterface其源码可看到
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
具体其源码中的注解为
- 使用
@Documented标注了,在生成javadoc的时候就会把@Documented注解给显示出来,但其实也没啥用处,一个标识而已 @Retention作用是定义被它所注解的注解保留多久,RetentionPolicy.RUNTIME注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在@Target作用于接口中
对于Target的补充:
| 参数 | 描述 |
|---|---|
| CONSTRUCTOR | 构造器 |
| FIELD | 域 |
| LOCAL_VARIABLE | 局部变量 |
| METHOD | 方法 |
| PACKAGE | 包 |
| PARAMETER | 参数 |
| TYPE | 类、接口(包括注解类型) 或enum声明 |
使用方法
具体如何使用该代码,只需要在接口上定义该注解即可
@FunctionalInterface
public interface Interface {
public void do();
}
如果使用两个接口就会出错
//错误展示
@FunctionalInterface
public interface Interface {
public void do();
public void love();
}
正确展示
//正确展示
@FunctionalInterface
public interface Interface {
public void do();
// java.lang.Object中的方法不是抽象方法
public boolean equals(Object var);
// default不是抽象方法
public default void defaultlove(){
}
// static不是抽象方法
public static void love(){
}
}
通过如上方法
可以确信这个注解的正确规则为
- 注解在接口上
- 被注解的接口有且只有一个抽象方法
- 被注解的接口可以有默认方法/静态方法,或者重写Object的方法
更多推荐


所有评论(0)