考虑以下代码片段:
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");
}
我无法理解方法调用歧义错误背后的原因
fun(String::toUpperCase)
。
由于
String::toUpperCase
本身的两个重载版本与 Comparator 类中的 int compare(String s1, String s2)
不兼容,那么编译器为什么首先会抱怨歧义呢?
我在这里遗漏了什么吗?
toUpperCase
有一个不带参数的重载,以及另一个带一个参数的重载 (Locale
)。
这使得表达式
String::toUpperCase
成为 inexact 方法引用表达式。该表达式可以指无参数重载,也可以指单参数重载。
两个
fun
都被确定为“潜在适用”,特别是因为这个条款:
方法引用表达式可能与功能接口类型兼容
如果,其中T
的函数类型为 n,则至少存在一个潜在的 当方法引用表达式的目标是时适用的方法 元数为 n 的函数类型,且满足以下条件之一:T
- 方法引用表达式的形式为
和至少一个可能适用的 方法要么是 (i) 静态并支持数量 n,要么 (ii) 非静态 并支持数量 n-1。ReferenceType :: [TypeArguments] Identifier
- [无关]
String::toUpperCase
可能与 Function<String, String>
兼容,因为 Function<String, String>
的元数为 1(采用一个参数),并且 toUpperCase
是非静态的并且具有无参数重载。
String::toUpperCase
可能与 Comparator<String>
兼容,因为 Comparator<String>
的元数为 2,并且 toUpperCase
是非静态的并且具有单参数重载。请注意,此步骤根本不检查参数类型或返回类型。参数类型是 Locale
并不重要,但实际上需要 String
。
找到潜在适用的方法后,我们继续通过严格调用识别适用的匹配数量方法。这就是出问题的地方。还记得
String::toUpperCase
是如何成为 inexact 方法引用的吗?这意味着它与适用性无关 - 编译器在此步骤中根本不考虑方法引用。另请参阅另一个问题,该问题还涉及导致重载解析错误的不精确方法引用表达式。
因此,两个
fun
都可以通过严格调用来应用。下一步是找到最具体的方法。此步骤考虑子类型,例如 String
比 Object
更具体。但是Comparator<String>
与Function<String, String>
无关,所以我们找不到最的具体方法,就会出现错误。