Java 在使用三元运算符 ('?') 时是否无法推断出泛型类型参数?

2022-09-03 02:26:18

为什么编译器能够确定赋值的泛型类型参数,而不能确定三元运算符 ()的泛型类型参数??

我有一个关于编译器能够在“直接”赋值的情况下推断出泛型类型参数的问题,但在三元运算符()的情况下失败。我的例子使用番石榴的类来表达我的观点,但我认为潜在的问题是通用的,不限于.?OptionalOptional

Optional具有泛型函数:absent()

public static <T> Optional<T> absent();

我可以将 一个 分配给 :Optional<T>Optional<Double>

// no compiler error
final Optional<Double> o1 = Optional.absent();

编译器如何意识到,在这种情况下应该是这样。因为在使用三元运算符()时,我需要将编译器作为泛型参数专门告诉我们TDouble?Integer

// Type mismatch: cannot convert from Optional<capture#1-of ? extends Object> to Optional<Integer>
final Optional<Integer> o2 = true
    ? Optional.of(42)
    : Optional.<Integer>absent();

否则我收到以下错误

类型不匹配:无法从 转换为Optional<capture#1-of ? extends Object>Optional<Integer>

为什么“直接”赋值和使用三元运算符之间有区别?还是我错过了其他东西?


答案 1

由于类型推断规则,三元表达式似乎不会从返回类型推断类型参数。三元表达式的类型取决于其操作数的类型。但其中一个操作数具有未确定的类型参数 ()。此时,三元表达式仍然没有类型,因此它不会影响类型参数。Optional.absent()

您还可以查看此错误报告以获取更多信息。您可以查看JLS

条件表达式的类型是应用捕获转换的结果 (??5.1.10) 至润滑油(T1, T2)

以下是JLS所说的:

如果方法结果发生在将赋值到类型 S 的上下文中,则设 R 是该方法的声明结果类型,并设 R' = R[T1 = B(T1) ...Tn = B(Tn)],其中B(Ti)是上一节中推断的Ti的类型,如果没有推断出任何类型,则为Ti。


答案 2

问题是 ternery 运算符的结果被分配给 o2。编译器无法跨多个操作推断出类型。

基本上,我认为你写的是以下简称:

Optional<?> tmp = true ? Optional.of(42): Optional.absent();
final Optional<Integer> o2 = tmp;

第二行的转换是问题所在。


推荐