方法引用的歧义问题:调用fun(String::toUpperCase)为何报编译错误?
方法引用引发重载歧义的原因解析
先看你的代码:
public static void main(String[] args) { Function<String, String> function = String::toUpperCase; //OK // Comparator<String> comparator = String::toUpperCase; //Compilation error(makes sense, as String.toUpperCase(Locale locale) & String.toUpperCase() are not compatible) fun(String::toUpperCase); // java: reference to fun is ambiguous } public static void fun(Function<String, String> function) { // String apply(String obj) System.out.println("Function"); } public static void fun(Comparator<String> comparator) { // int compare(String s1, String s2) System.out.println("Comparator"); }
你困惑的点在于:明明String::toUpperCase的两个重载都没法适配Comparator的compare方法,为什么调用fun时还会报歧义?核心原因在于Java编译器的重载解析流程和方法引用适配的检查阶段:
第一步:重载候选筛选
编译器在处理fun(String::toUpperCase)时,会先找出所有可访问且参数匹配的fun重载版本,也就是fun(Function)和fun(Comparator)这两个候选。
这一步的检查是初步的,不会做完整的方法引用与函数式接口的兼容性验证:- 对于
fun(Function):Function的apply方法是单参数返回String,String::toUpperCase的无参版本可以完美适配(相当于(s) -> s.toUpperCase()),所以这个候选显然可行。 - 对于
fun(Comparator):Comparator的compare是双参数返回int。编译器看到String::toUpperCase有一个带Locale参数的重载版本,这个方法加上调用它的实例(String),刚好是两个参数(和compare的参数数量一致)。此时编译器不会立刻检查参数类型(String vs Locale)和返回值类型(String vs int)的不匹配,只是认为“参数数量匹配,存在适配的可能性”,因此把这个候选也保留了下来。
- 对于
第二步:无法确定最优候选
当两个候选方法都通过了初步筛选,编译器需要选出最具体的那个。但Function和Comparator是平级的接口,没有继承关系,不存在“更具体”的优先级,因此编译器无法确定你要调用哪个fun,最终抛出歧义错误。
而你直接赋值Comparator<String> comparator = String::toUpperCase时,目标类型是明确的,编译器会立刻做完整的兼容性检查,发现参数类型和返回值都不匹配,所以直接报编译错误,不会进入重载选择的流程。
内容的提问来源于stack exchange,提问作者Rohan Jaiswal
相关产品推荐
相关产品推荐

