接口的默认方法
/* 从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的方法