java - 为什么 Java 不能推断父类(super class)型?

标签 java type-inference

我们都知道龙延伸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来自具有此类签名的函数? 它不会为您进行向下转型。

NumberLong 的父类(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/

相关文章:

java - Byte Buddy installOn API 给出错误 : adding retransformable transformers is not supported?

java - 解决循环引用

javascript - 如何向 Web 界面通知变量的状态?

java - JDK 7 中的类型推断比 JDK 6 更严格?

typescript - TS 错误地推断路口类型

java-8 - JDK8 类型推断问题

java - com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException : Unrecognized field

java - 使用约束布局针对不同的屏幕尺寸进行设计

Swift 不可能的类型推断

haskell - 如何将 `forall a. a -> a` 转换回 `a -> a` ?