我们都知道龙延伸Number
。那么为什么这不能编译呢?
以及如何定义方法with
以便程序无需任何手动转换即可编译?
import java.util.function.Function;
public class Builder<T> {
static public interface MyInterface {
Number getNumber();
Long getLong();
}
public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue) {
return null;//TODO
}
public static void main(String[] args) {
// works:
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// works:
new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
// works:
new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
// works:
new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
// compilation error: Cannot infer ...
new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
// compilation error: Cannot infer ...
new Builder<MyInterface>().with(MyInterface::getNumber, Long.valueOf(4));
// compiles but also involves typecast (and Casting Number to Long is not even safe):
new Builder<MyInterface>().with( myInterface->(Long) myInterface.getNumber(), 4L);
// compiles but also involves manual conversion:
new Builder<MyInterface>().with(myInterface -> myInterface.getNumber().longValue(), 4L);
// compiles (compiler you are kidding me?):
new Builder<MyInterface>().with(castToFunction(MyInterface::getNumber), 4L);
}
static <X, Y> Function<X, Y> castToFunction(Function<X, Y> f) {
return f;
}
}
- Cannot infer type argument(s) for
<F, R> with(F, R)
- The type of getNumber() from the type Builder.MyInterface is Number, this is incompatible with the descriptor's return type: Long
有关用例,请参阅:Why is lambda return type not checked at compile time
最佳答案
这个表达式:
new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
可以重写为:
new Builder<MyInterface>().with(myInterface -> myInterface.getNumber(), 4L);
考虑方法签名:
public <F extends Function<T, R>, R> Builder<T> with(F getter, R returnValue)
-
R
将被推断为Long
-
F
将是Function<MyInterface, Long>
并且您传递一个方法引用,该引用将被推断为 Function<MyInterface, Number>
这是关键 - 编译器应该如何预测您实际上想要返回 Long
来自具有此类签名的函数? 它不会为您进行向下转型。
自 Number
是 Long
的父类(super class)和Number
不一定是Long
(这就是它无法编译的原因) - 您必须自己显式转换:
new Builder<MyInterface>().with(myInterface -> (Long) myInterface.getNumber(), 4L);
制作F
成为Function<MyIinterface, Long>
或者像您一样在方法调用期间显式传递通用参数:
new Builder<MyInterface>().<Function<MyInterface, Number>, Number> with(MyInterface::getNumber, 4L);
并且知道R
将被视为 Number
并且代码将编译。
关于java - 为什么 Java 不能推断父类(super class)型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58378037/