【发布时间】:2019-11-28 18:55:09
【问题描述】:
我遇到了一条奇怪的错误消息,我认为它可能不正确。考虑以下代码:
public class Overloaded {
public interface Supplier {
int get();
}
public interface Processor {
String process(String s);
}
public static void load(Supplier s) {}
public static void load(Processor p) {}
public static int genuinelyAmbiguous() { return 4; }
public static String genuinelyAmbiguous(String s) { return "string"; }
public static int notAmbiguous() { return 4; }
public static String notAmbiguous(int x, int y) { return "string"; }
public static int strangelyAmbiguous() { return 4; }
public static String strangelyAmbiguous(int x) { return "string"; }
}
如果我有一个看起来像这样的方法:
// Exhibit A
public static void exhibitA() {
// Genuinely ambiguous: either choice is correct
load(Overloaded::genuinelyAmbiguous); // <-- ERROR
Supplier s1 = Overloaded::genuinelyAmbiguous;
Processor p1 = Overloaded::genuinelyAmbiguous;
}
我们得到的错误是完全有道理的; load() 的参数可以分配给任何一个,所以我们得到一个错误,指出方法调用不明确。
相反,如果我有一个看起来像这样的方法:
// Exhibit B
public static void exhibitB() {
// Correctly infers the right overloaded method
load(Overloaded::notAmbiguous);
Supplier s2 = Overloaded::notAmbiguous;
Processor p2 = Overloaded::notAmbiguous; // <-- ERROR
}
对load() 的调用很好,正如预期的那样,我无法将方法引用分配给Supplier 和Processor,因为它没有歧义:Overloaded::notAmbiguous 不能分配给p2。
现在是奇怪的。如果我有这样的方法:
// Exhibit C
public static void exhibitC() {
// Complains that the reference is ambiguous
load(Overloaded::strangelyAmbiguous); // <-- ERROR
Supplier s3 = Overloaded::strangelyAmbiguous;
Processor p3 = Overloaded::strangelyAmbiguous; // <-- ERROR
}
编译器抱怨对load() 的调用不明确(error: reference to load is ambiguous),但与图表A 不同的是,我不能将方法引用分配给Supplier 和Processor。如果它真的模棱两可,我觉得我应该能够将 s3 和 p3 分配给这两种重载参数类型,就像在图表 A 中一样,但我在 p3 上收到一个错误,指出 error: incompatible types: invalid method reference。 Exhibit C 中的第二个错误是有道理的,Overloaded::strangelyAmbiguous 不能分配给 Processor,但如果它不可分配,为什么它仍然被认为是模棱两可的?
在确定选择哪个重载版本时,方法引用推断似乎只查看 FunctionalInterface 的数量。在变量赋值中,检查arity 和类型的参数,导致重载方法和变量赋值之间存在这种差异。
在我看来,这就像一个错误。如果不是,那么至少错误消息是不正确的,因为当两个选项之间只有一个是正确的时,可以说没有歧义。
【问题讨论】:
-
我可以复制,但是请您删除“exhibit A”和“exhibit B”吗?我不认为它们并没有真正增加对问题的理解。展览 C 本身就很好。
-
请记住,人类必须维护此代码。即使编译器可以解决,我更喜欢
loadProcessor和loadSupplier这样的名称,所以我不必考虑它。 -
@markspace 请记住,作为人类,我们喜欢了解它的实际工作原理
-
@ArnaudClaudel 是的,我知道,这就是为什么它是评论,而不是答案。可以问,但这个问题主要是学术性的。我希望没有人以这种方式编写生产代码。
标签: java overloading method-reference functional-interface arity