为什么编译器能够确定赋值的泛型类型参数,而不是三元运算符(?)?
我有一个问题,关于编译器能够在"直接"赋值的情况下推导出泛型类型参数,但在三元运算符(?)的情况下失败.我的例子使用了Guava的Optional类来表达我的观点,但我认为潜在的问题是通用的而不仅限于Optional.
Optional有一个通用的功能absent():
public static <T> Optional<T> absent();
Run Code Online (Sandbox Code Playgroud)
我可以指定Optional<T>一个Optional<Double>:
// no compiler error
final Optional<Double> o1 = Optional.absent();
Run Code Online (Sandbox Code Playgroud)
编译器如何实现,在这种情况下T应该Double如此.因为在使用三元运算符(?)时,我需要将编译器专门告诉我们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();
Run Code Online (Sandbox Code Playgroud)
否则我收到以下错误
类型不匹配:无法转换
Optional<capture#1-of ? extends Object>为Optional<Integer>
为什么"直接"分配和使用三元运算符之间存在差异?或者还有其他我想念的东西?
由于类型推断规则,三元表达式似乎不会从返回类型推断出类型参数.三元表达式的类型取决于其操作数的类型.但其中一个操作数具有未确定的类型参数(Optional.absent()).此时,三元表达式仍然没有类型,因此它不会影响类型参数.
条件表达式的类型是将捕获转换(?? 5.1.10)应用于lub(T1,T2)的结果
这是JLS所说的:
如果方法结果发生在它将被赋值转换为类型S的上下文中,那么让R成为方法的声明结果类型,并让R'= R [T1 = B(T1)... Tn = B(Tn)]其中B(Ti)是上一节中Ti的推断类型,如果没有推断出类型,则为Ti.
问题是,ternery操作员的结果被分配给o2.编译器无法在多个操作中推断出类型.
基本上我认为你写的简短形式:
Optional<?> tmp = true ? Optional.of(42): Optional.absent();
final Optional<Integer> o2 = tmp;
Run Code Online (Sandbox Code Playgroud)
第二行的转换是问题所在.