1. JDK8接口新增的两个方法
jdk8之前的接口
interface 接口名 {
静态常量;
抽象方法
}
JDK8对接口的增强,接口还可以有默认方法和静态方法
JDK8接口:
interface {
静态常量;
抽象方法;
默认方法;
静态方法;
}
1.1 接口默认方法
1.1.1 定义格式
interface 接口名{
修饰符 default 返回值类型 方法名(){
body
}
}
1.1.2 使用
方式一:实现类直接调用接口的默认方法
方式二:实现类也可以重写接口的默认方法
例如:定义三个接口A、B、C,B和C都实现A
package com.hm.lambda;
public interface AA {
public default void test01(){
System.out.println("接口AA的默认方法");
}
}
package com.hm.lambda;
// 实现类可以直接使用AA的默认方法
public class BB implements AA{
}
package com.hm.lambda;
// 实现类可以重写AA的默认方法
public class CC implements AA {
@Override
public void test01() {
System.out.println("我是CC重写的方法");
}
}
然后在分别调用CC和BB中的方法
public static void main(String[] args) {
BB bb = new BB();
bb.test01();
CC cc = new CC();
cc.test01();
}
运行结果如图:
1.2 接口静态方法
为了方便扩展,JDK8接口新增了静态方法
1.2.1 定义格式
interface 接口名 {
修饰符 static 返回值类型 方法名(){
代码;
}
}
1.2.2 使用
直接使用 接口名.静态方法 调用即可
例如:
package com.hm.lambda;
public interface AA {
public default void test01(){
System.out.println("接口AA的默认方法");
}
public static void test02(){
System.out.println("静态方法test02");
}
}
调用:
public static void main(String[] args) {
AA.test02();
}
注意:接口中的静态方法,不能被继承,不能被重写
1.2.3 接口默认方法与静态方法的区别
1)默认方法通过实例调用,静态方法通过接口名调用
2)默认方法可以被继承,实现类可以直接使用接口默认方法,也可以重写默认方法
3)静态方法不能被继承,实现类不能重写接口静态方法,只能使用接口名调用
小结:什么时候定义默认方法,什么时候定义静态方法了?当该方法需要被继承或者覆写的时候,就用default方法,否则用静态方法。
2. 认识函数式接口
函数式接口(FunctionalImplement)是一种只含有一个抽象方法声明的接口,但是可以有多个非抽象方法的接口。类似于Java中的Marker Interface标记类型接口,比如java.io.Serializable等都是没有方法声明或属性声明的接口,主要用于通过instanceof就直接能探测一个实例是否是一个特定接口的实例。
函数式接口也是一个接口,该接口中只能有一个抽象的方法,这种类型的接口也称之为SAM接口。
@FunctionalInterface
public interface LamFilter {
Boolean filter(Apple apple);
}
Java 8为函数式接口引入了一个新注解@FunctionalInterface,主要用于编译级错误检查,加上该注解,当你写的接口不符合函数式接口定义的时候,编译器会报错。加不加@FunctionalInterface对于接口是不是函数式接口没有影响,该注解只是提醒编译器去检查该接口是否仅包含一个抽象方法。如上例所示,在接口定义上加上注解@FunctionalInterface声明该接口是一个函数式接口。
2.1 函数式接口的特性
2.1.1 允许定义默认方法
默认方法不是抽象的,有一个默认的实现,通过实现类直接调用,不需要实现类实现该方法,提高了扩展性!
@FunctionalInterface
interface HelloWorld {
void print(String str);
//默认方法
default void print2(String message) {
System.out.println(message);
}
}
注意:默认(default)方法只能通过接口的实现类来调用,不需要实现方法,也就是说接口的实现类可以继承或者重写默认方法。
2.1.2 允许定义静态方法
静态方法不能是抽象方法,是一个已经实现了的方法,直接接口调用。跟普通的static方法是一样的,不需要实现类去调用
@FunctionalInterface
interface HelloWorld {
void print(String str);
//静态方法
static void print3(String message) {
System.out.println(message);
}
}
注意:静态(static)方法只能通过接口名调用,不可以通过实现类的类名或者实现类的对象调用。就跟普通的静态类方法一样,通过方法所在的类直接调用
2.1.3. 允许定义java.lang.Object里的public方法
这些方法对于函数式接口来说,不被当成是抽象方法(虽然它们是抽象方法);因为任何一个函数式接口的实现,默认都继承了Object类,包含了来自 java.lang.Object里对这些抽象方法的实现;
2.1.4 允许子接口继承多个父接口
允许子接口继承多个父接口,但每个父接口中都只能存在一个抽象方法,且必须是相同的抽象方法
注意:函数式接口,有且仅有一个抽象方法,Object的public方法除外。
3. 自定义函数式接口
3.1 自定义参数个数的函数式接口
我们发现,JDK提供的BiFunction最多只有2个参数,如果我们有3个参数的该怎么办了?这个时候就需要使用自定义的函数式接口来实现了!
例如:
Orage.java
package com.bjc.demo1;
public class Orage {
private String color;
private Double price;
private Double weight;
public Orage(String color, Double price, Double weight) {
this.color = color;
this.price = price;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public Double getWeight() {
return weight;
}
public void setWeight(Double weight) {
this.weight = weight;
}
}
自定义函数接口ThreeFunction:
package com.bjc.lambda.demo1;
@FunctionalInterface
public interface ThreeFunction<T,U,V,R> {
R apply(T t,U u,V v);
}
函数式接口的使用:
ThreeFunction<String,Double,Double,Orage> tFunc = Orage :: new;
Orage orage = tFunc.apply("red", 3.99, 0.78);
System.out.println(orage);
3.2 自定义无参数函数式接口
接口定义:
interface InterfaceExample{
Example create(String name);
}
使用:
public static void main(String[] args) {
InterfaceExample com = Example::new;
Example bean = com.create("hello world");
System.out.println(bean.name);
}
注意:Example是一个pojo类