作者:chengco


前言

因为Java8引入了函数式接口,对于Java类的方法来说都可以看作是函数, 比如:Comparator comparatorFunction = Integer::compareTo。而方法引用只是一个语法糖,本质上通过方法引用所得到的还是函数对象。所以问题是Java编译器是如何得知Integer::compareTo函数的接口是Comparator而不是其他的?回答这个问题需要了解方法引用的用法及函数类型匹配机制。 方法引用类别 Javase文档中说明方法引用包括四种:静态方法引用 类名::静态方法(ContainingClass::staticMethodName )

特定对象的实例方法引用 实例::实例方法(containingObject::instanceMethodName)

任意对象的实例方法引用(Reference to an instance method of an arbitrary object of a particular type) 类名::实例方法(ContainingType::methodName)

构造函数引用 ClassName::new 类名::new

以Integer类为例, 四种方法引用分别为:

Integer instance = Integer.valueOf(10);

BiFunction parseIntFunction = Integer::parseInt; //静态方法引用

Function compareToInstanceFunction = instance::compareTo;//特定对象的实例方法引用

Comparator comparatorFunction = Integer::compareTo; //任意对象的实例方法引用

Comparator compareToIgnoreCase = String::compareToIgnoreCase; //任意对象的实例方法引用

Function constructorFunction = Integer::new;//构造函数方法引用

IntFunction intConstructorFunction = Integer::new;//构造函数方法引用

函数类型的匹配机制

函数类型的匹配:方法名不重要,根据方法参数来决定是否符合, 比如:Integer::compareTo和String::compareToIgnoreCase

不管哪种方法引用,可能匹配到多个函数接口, 比如:上例中的Integer::new

静态方法引用/构造函数方法引用不涉及实例,所以匹配函数类型,直接根据参数个数和类型

特定对象的实例方法引用,因为是在某一个实例上的方法引用,所以匹配函数类型,也直接根据参数个数和类型

任意对象的实例方法引用,这个比较特殊,它是通过类名去获取的,但是执行的时候需要知道在哪个实例上执行,所以它在匹配函数类型时,会增加一个自身类型的参数作为第一个参数,比如:上例中的Integer::compareTo,只有一个参数(Integer i),但是当匹配函数时,会拿 (Integer i,Integer j)去匹配。这个例子中正好参数类型和自身类型都是Integer,所以不太容易区分。举个容易理解的例子:BiFunction stringBiFunction = String::substring;, subString只有一个int参数,但是会匹配到BiFunction,且第一个参数是String类型。