在Java中可以重载方法,造成多个方法有相同的方法名,但签名确不一样。这在推断参数类型时会带来问题,因为系统可能会推断出多种类型。这时,javac会挑出最具体的类型。如下文中的方法调用在选择定义的重载方法时,输出String,而不是Object
overloadedMethod("abc");
对应的接口定义
private void overloadedMethod(Object o) {
System.out.println("Object");
}
private void overloadMethod(String s) {
System.out.println("String");
}
BinaryOperator是一种特殊的BiFunction类型,参数的类型和返回值的类型相同。比如,两个整数相加就是一个BinaryOperator。Lambda表达式的类型就是对应的函数接口类型,因此,将Lambda表达式作为参数传递时,情况也依然如此。操作时可以重载一个方法,分别接受BinaryOperator和该接口的一个子类作为参数。调用这些方法时,Java推导出的Lambda表达式的类型正是最具体的函数接口的类型。
@Slf4j
public class lambdaTest {
private interface IntegerBiFunction extends BinaryOperator<Integer> {
}
private interface NanoIntegerBiFunction extends IntegerBiFunction {
}
private void overloadedMethod(BinaryOperator<Integer> lambda) {
System.out.println("BinaryOperator");
}
private void overloadedMethod(NanoIntegerBiFunction lambda) {
System.out.println("NanoIntegerBiFunction");
}
private void overloadedMethod(IntegerBiFunction lambda) {
System.out.println("IntegerBinaryOperator");
}
@Test
public void overloadTest() {
overloadedMethod((x, y) -> x + y);
}
}
输出结果为
NanoIntegerBiFunction
//重载方法导致的编译错误
private interface IntPredicate {
public boolean test(int value);
}
private void overloadMethod2(Predicate<Integer> predicate) {
System.out.println("Predicate");
}
private void overloadMethod2(IntPredicate predicate) {
System.out.println("IntPredicate");
}
@Test
public void overloadErrTest() {
overloadMethod2(((Predicate<Integer>) (x) -> x > 10));
overloadMethod2((IntPredicate) (x) -> x > 10);
//error code
overloadMethod2((x) -> x > 10);
/*
Ambiguous method call. Both
overloadMethod2 (Predicate<Integer>) in lambdaTest and
overloadMethod2 (IntPredicate) in lambdaTest match
*/
}
传入overloadedMethod方法的Lambda表达式和两个函数接口Predicate、IntPredicate在类型上都是匹配的。在这段代码块中,两种情况都定义了相应的重载方法,这时,javac就无法编译,在错误报告中显示Lambda表达式被模糊调用。IntPredicate没有继承Predicate,因此编译器无法推断出哪个类型更具体。
将Lambda表达式强制转换为IntPredicate或Predicate类型可以解决这个问题,至于转换为哪种类型则取决于要调用哪个函数接口