public class Main {
List<List<Integer>> f0() {
return List.of(List.of(1L));
}
List<List<Integer>> f1() {
return List.of((List) List.of(1L));
}
List<List<Integer>> f2() {
var r = List.of((List) List.of(1L));
return r;
}
List<List<Integer>> f3() {
return List.of((List) List.of(1L), List.of(1L));
}
List<List<Integer>> f4() {
return List.of((List) List.of(1L), (List) List.of(1L));
}
}
在上面的代码中,
f1
和f4
可以编译,而f0
、f2
和f3
则不能编译。f0
无法编译:它需要 List<List<Integer>>
但它看到 List<List<Long>>
。但我不知道为什么其他人会这样做。
f2:
incompatible types: List<List> cannot be converted to List<List<Integer>>
f3:
error: incompatible types: inference variable E has incompatible bounds
return List.of((List) List.of(1L), List.of(1L));
^
equality constraints: Integer
lower bounds: Long
where E is a type-variable:
E extends Object declared in method <E>of(E)
在每个函数中,返回的表达式的类型到底是什么?为什么Java会有这样的行为?根据 JLS 的说法,到底发生了什么?如果重要的话我会使用 Java 17。
f2
和f0
之间的区别在于List.of
不在f2
中的赋值上下文中,§14.4.1:
如果 LocalVariableType 为
,则将var
视为初始化表达式的类型(当将其视为未出现在赋值上下文中时...)T
因此,调用不是聚表达式。它不满足 §15.12:
中作为多元表达式的要求如果满足以下所有条件,则方法调用表达式是多元表达式:
- 调用出现在赋值上下文或调用上下文中
- ...
这意味着类型推断不再考虑目标类型 (§15.12.2.6)。
如果所选方法是泛型并且方法调用不提供显式类型参数,则按照第 18.5.2 节中的指定推断调用类型。
在这种情况下,如果方法调用表达式是多表达式,则其与目标类型的兼容性由§18.5.2.1确定。
跳过了整个 §18.5.2.1,它会添加一些关于
Integer
的约束。
但是,如果将
List.of
放在 return 语句中,则它 is 位于赋值上下文中 (§14.17):
如果带有值 Expression 的返回语句的返回目标是声明返回类型
的方法,并且 Expression 的类型与 T 不可分配兼容(第 5.2 节),则这是一个编译时错误。T
(第 5.2 节是赋值上下文部分)
更通俗地说,Java 不会查看所有使用
r
来推断 List.of
的类型参数的地方。它只查看调用List.of((List) List.of(1L))
。它被分配给 var
,因此类型推断结果为 List<List>
。类型推断没有理由在其中随机添加 <Integer>
。
当然,
List<List>
与List<List<Integer>>
不兼容,就像List<Dog>
与List<Animal>
不兼容一样。
对于
f3
,存在相互冲突的约束。我将使用 E
来引用外部 List.of
调用的类型参数,并使用 E1
和 E2
来引用第一个和第二个内部 List.of
调用的类型参数。
因为外部
List.of
位于 return 语句中,所以适用 §18.5.2.1,并且 E
的下限为 List<Integer>
。
推断 E1
的下限为 Long
,则适用 §18.5.2.1,并且目标类型是原始 List
,即您要转换到的类型。没有什么问题,我们继续。
第一个参数中的原始
List
给出了 List
的上限 E
。没关系 - 这里没有冲突。
在
f4
中,第二个参数和E2
也会发生同样的事情,所以没有问题。
在
f3
中,当推断E2
时,适用§18.5.2.1,由于List<Integer>
的约束,目标类型为E
。这给 E2
添加了一个等式约束。参数 1L
还为 Long
添加了 E2
的下限。
这就是冲突所在。不存在同时满足
== Integer
和 >= Long
的类型。