这个 Function.identity()
返回函数, Function<T, T>
始终返回其输入参数(即标识函数)。
但是作为一个静态方法,它如何知道返回哪个具体参数来代替类型参数呢 T
当它甚至不需要任何输入的时候?
我的思维过程:
Map idToPerson = people.collect( Collectors.toMap( (person -> person.getID() , Function.identity() ) );
问题:那么编译器是如何发现的呢 Function.identity()
应该会回来的 Function<element of 'people' stream, element of 'people' stream>
流,尽管没有输入?
根据openjdk,实现类似于:
static <T> Function<T, T> identity()
{
return t -> t;
}
试图缩小我的问题范围:
你怎么知道的 Function.identity()
知道具体的数据类型 t
在 t -> t
(顺便说一句,这是lambda Function<T, T>
)是吗?
1条答案
按热度按时间i2byvkas1#
java类型的推理算法是基于推理变量上约束公式的解析。java语言规范的第18章对此进行了详细描述。有点牵扯。
非正式地说,上述例子的推理大致如下:
我们有一个
Function.<T>identity()
. 因为大多数类型参数都被命名为T
,与jls一致,我将使用希腊字母表示推理变量。在这个初始表达式中T :: α
. 我们有什么限制α
?好
identity()
返回的示例Function<α,α>
用作…的论据toMap
.所以现在我们有了约束条件
{α :> T, α <: K}
(其中:>
表示的超类型,反之亦然)。现在需要我们推断T
以及K
在这个表达式中,我们称之为β
以及γ
,所以:{α :> β, α <: γ}
. 为了避免陷入细节的泥沼,让我们一起努力β
只是。toMap
然后将收集器作为参数返回给Stream.collect
,这为我们提供了另一个约束来源:所以现在我们知道了
{β :> T}
. 但是在这里T
也需要推断,所以它变成了一个推断变量,我们有{β :> δ}
.这就是它开始展开的地方,因为类型参数
T
for方法collect
指参数T
在Stream<T>
. 假设流被定义为Stream<Person>
,现在我们有了{δ=Person}
我们可以减少如下:{β :> δ} => {β :> Person}
(β
是Person
);{α :> β} => {α :> (β :> Person)} => {α :> Person)}
(α
是Person
);所以通过推理的过程我们发现
Function.identity
必须是Person
或者是Person
. 类似的过程α <: γ
会屈服的{α <: Person}
(如果指定了返回类型)。所以我们有两个限制:α
必须是Person
或者是Person
;α
必须是Person
或者是Person
;显然,满足所有这些约束的唯一类型是
Person
.