持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
在掌握lambda表达式的使用后, 就不得不谈谈方法引用, 他和lambda表达式有什么关系?
还记得我们在上一节讲到的lambda表达式的常用场景: lambda表达式作为一个实现了接口抽象方法的子类对象, 作为参数传入方法中, 相当于给方法传入了一个函数, 这是函数式编程思想的实践.
你可能不记得具体细节了, 我们来回顾一下
有个接口:
interface IPrintStr{
void clockin(int kilometre);
}
用lambda表达式来实现接口, 并且调用:
public class Demo{
// 作用是调用接口的方法.
private static void exerciseReminder(IPrintStr data){
data.clockin(2);
}
public static void main(String[] args) {
// lambda表达式的本质为匿名函数,并重写了其中的抽象方法
// lambda表达式定义了在exerciseReminder中调用的方法的具体实现
exerciseReminder(x-> System.out.println("今天打卡任务:"+x+"公里"));
exerciseReminder(x-> System.out.println(x+"公里已完成"));
}
}
这么看好像lambda表达式也没多简洁? 如果你还有两个其他方法: task和finishtask
public static void task(int kilometer){
System.out.println("今天打卡任务: "+kilometer+"公里!");
}
public static void finishtask(int kilometer){
System.out.println(kilometer+"公里已完成!");
}
通过方法引用, 你可以简化代码:
public static void main(String[] args) {
exerciseReminder(Demo::task);
exerciseReminder(Demo::finishtask);
}
这里的方法引用, 形式两个冒号, 后面跟已有的方法名(如task, finishtask), 冒号前是该方法所定义的位置, 如果定义在Demo类中, 就用Demo::task表示方法引用.
具体解析为什么能这样做:
这里相当于在exerciseReminder中传入一个子接口, 子接口实现了父接口的抽象方法:
// 传入的子接口用匿名内部类对象表示相当于:
new IPrintStr{
void clockin (int kilometre){
// 如果是task方法的引用, 就是
System.out.println("今天打卡任务: "+kilometer+"公里!");
// 如果是finishtask方法引用, 就相当于
System.out.println(kilometer+"公里已完成!");
}
}
方法引用exerciseReminder(Demo::task);
这里exerciseReminder要接收一个IPrintStr接口对象, 然后在exerciseReminder中调用IPrintStr接口的clockin方法, 但问题是, IPrintStr是个接口, 他只定义了clockin方法, 但没写具体实现, 所以exerciseReminder必须接收一个实现了该方法的IPrintStr的具体子类.
由于该IPrintStr接口的功能单一,我们既可以先创建一个子实现对象,然后传入exerciseReminder方法,也可以利用lambda表达式简化代码编写,更直接的,既然关键点在于该接口的抽象方法需要具体实现, 那么我们可以直接传入一个方法当做该抽象方法的具体实现, 这就叫做方法引用!