定义
当lambda表达式体中只涉及到一个方法的调用,我们就可以对这个lambda表达式进行进一步的简化,而这个简化的结果就是方法引用。对于什么是lambda表达式请参看我这篇文章:
什么是lambda表达式.
具体的代码展示:
ActionListener a = s -> System.out.println(s);
比如以上这个lambda表达式他只涉及到System.out对象的println方法调用,所以可以简化成方法引用,如下:
ActionListener s = System.out::println;
表达式System.out::println就是方法引用。他会指示编译器生成一个函数式接口的实例,并且覆盖接口中唯一的抽象方法来调用你给定的这个方法,也就是你给定的这个方法就是对抽象方法的实现,到时候这个接口类型的对象调用抽象方法时执行的就是方法引用的方法。
注意
和lambda表达式一样,方法引用也不是一个对象,只是在用他们给一个函数式接口的变量赋值时会生成一个该函数式接口的对象。
对于方法的重载,他会根据你函数式接口中的唯一的抽象方法的参数列表来进行调用。什么意思呢?请看下面:
public interface AA {//我定义的函数式接口
void p(String s);
}
public static void main(String[] args) {//主方法
AA a = s -> System.out.println(s);//lambda表达式
AA b = System.out::println;//方法引用
a.p("ss");
b.p("bbb");
}
我们知道System.out对象中有多个重载的println方法,包含有多个参数的,一个参数的,没有参数的等。那么在方法引用中到底会调用哪个println方法呢?看的就是接口AA中的p方法的参数列表,p方法中的参数列表中有一个参数,那他就会调用那个只有一个参数的println方法。注意这个方法引用的调用就是对p方法的实现,对象b调用p方法时执行的就是System.out.println(“bbb”);
方法引用的格式
-
object::instanceMethod
该格式等价的lambda表达式为x -> object.instanceMethod(x),lambda表达式参数作为方法的显示参数传入。例如:System.out::println 等价于 s -> System.out.println(s) -
Class::instanceMethod
该格式等价的lambda表达式为(x,y) -> x.instanceMethod(y)(这只是举个例),lambda表达式的第一个参数作为方法的隐式参数传入,第二个参数作为方法的显示参数传入,也可以没有第二个参数。 -
Class::staticMethod
该格式等价的lambda表达式为(x,y) -> Class.instanceMethod(x,y),lambda表达式的参数都会传入到方法中,例如:(x,y) -> Math.pow(x,y) -
this::instanceMethod
该格式等同于lambda表达式:x -> this.instanceMethod(x),也就是调用当前对象的方法。 -
super::instanceMethod
该格式等同于lambda表达式:x -> super.instanceMethod(x),调用当前对象的超类版本的方法。
以上就是方法引用的介绍,还有一点就是方法引用是对lambda表达式的进一步简化,任何方法引用都可以转换成lambda表达式,但不是任何的lambda表达式都可以简化成方法引用,只有在lambda表达式的体中的代码只存在一个方法的调用,没有其他代码才可以转化成方法引用。(以上为个人理解)
构造器引用
构造器引用和方法引用很类似,只不过将方法名换成了new操作符,例如:Employee::new 是Employee构造器的引用,如果构造器存在重载的话那具体调用哪个构造器呢?这就会根据上下文来推导出,也就是根据上下文中传入的参数列表来和构造器的参数列表进行匹配,从而选择调用。
也可以使用数组类型来创建构造器引用,例如:int[]::new 这就是一个整数类型数组的构造器引用,等价于lambda表达式:x -> new int[x],它会有一个参数表示数组的长度。