[英]How do generic types get inferred in Java?
The Function.identity()
returns a function, Function<T, T>
that always returns its input argument(ie identity function ). Function.identity()
返回一个 function, Function<T, T>
始终返回其输入参数(即标识 function )。
But being a static method, how does it know which concrete argument to return in place of type parameter T
when it doesn't even take any inputs?但是作为一个 static 方法,当它甚至不接受任何输入时,它如何知道返回哪个具体参数来代替类型参数
T
呢?
Illustration of my thought process:我的思考过程图解:
Map idToPerson = people.collect( Collectors.toMap( (person -> person.getID() , Function.identity() ) );
Question: So how does the compiler figure out that Function.identity()
is supposed to return Function<element of 'people' stream, element of 'people' stream>
stream despite having no inputs?问题:那么编译器如何确定
Function.identity()
应该返回Function<element of 'people' stream, element of 'people' stream>
ZF7B44CFAFD5C52223D5498196CA2 尽管没有输入?
According to the OpenJDK , the implementation is something like:根据OpenJDK ,实现类似于:
static <T> Function<T, T> identity()
{
return t -> t;
}
An attempt to narrow down my question:试图缩小我的问题:
How does Function.identity()
know what the concrete data type t
in t -> t
(btw this is the lambda Function<T, T>
) is? Function.identity()
如何知道具体的数据类型t
in t -> t
(顺便说一句,这是 lambda Function<T, T>
)是什么?
The Java type inference algorithm is based on the resolution of constraint formulas on inference variables . Java型推理算法是基于对推理变量的约束公式的解析。 It is described in detail in Chapter 18 of the Java Language Specification .
在 Java 语言规范的第 18 章中有详细描述。 It's a bit involved.
这有点涉及。
Informally, for the example above the reasoning would go roughly as follows:非正式地,对于上面的示例,推理将 go 大致如下:
We have an invocation of Function.<T>identity()
.我们调用了
Function.<T>identity()
。 Because most type parameters are named T
, and consistently with the JLS, I'll use Greek letters to denote inference variables.因为大多数类型参数都命名为
T
,并且与 JLS 一致,所以我将使用希腊字母来表示推理变量。 So in this initial expression T:: α
.所以在这个初始表达式中
T:: α
。 What constraints do we have on α
?我们对
α
有什么限制?
Well identity()
returns an instance of Function<α,α>
used as argument to toMap
.那么
identity()
返回一个Function<α,α>
的实例,用作toMap
的参数。
static <T,K,U> Collector<T,?,Map<K,U>> toMap(Function<? super T,? extends K> keyMapper,
Function<? super T,? extends U> valueMapper)
So now we have the constraints {α:> T, α <: K}
(where :>
means supertype of and vice-versa).所以现在我们有了约束
{α:> T, α <: K}
(其中:>
表示超类型,反之亦然)。 This now requires us to infer T
and K
in this expression, which we'll refer to as β
and γ
, so: {α:> β, α <: γ}
.现在需要我们在这个表达式中推断
T
和K
,我们将其称为β
和γ
,因此: {α:> β, α <: γ}
。 To avoid getting bogged down in details, let's work through β
only.为避免陷入细节困境,让我们只研究
β
。
toMap
then returns a collector as argument to Stream.collect
, which provides us with another source of constraints: toMap
然后返回一个收集器作为Stream.collect
的参数,这为我们提供了另一个约束来源:
collect(Collector<? super T,A,R> collector)
So now we know that {β:> T}
.所以现在我们知道
{β:> T}
。 But here T
also needs to be inferred, so it becomes an inference variable, and we have {β:> δ}
.但是这里的
T
也需要被推断,所以它成为一个推断变量,我们有{β:> δ}
。
This is where it starts unfolding, because the type parameter T
for method collect
refers to the parameter T
in Stream<T>
.这是它开始展开的地方,因为方法
collect
的类型参数T
引用Stream<T>
中的参数T
。 So assuming the stream was defined as Stream<Person>
, now we have {δ=Person}
and we can reduce as follows:所以假设 stream 被定义为
Stream<Person>
,现在我们有{δ=Person}
,我们可以减少如下:
{β:> δ} => {β:> Person}
( β
is a supertype of Person
); {β:> δ} => {β:> Person}
( β
是Person
的超类型);{α:> β} => {α:> (β:> Person)} => {α:> Person)}
( α
is a supertype of Person
); {α:> β} => {α:> (β:> Person)} => {α:> Person)}
( α
是Person
的超类型); So through the process of inference we figured out that the type variable for Function.identity
needs to be Person
or a supertype of Person
.因此,通过推理过程,我们发现
Function.identity
的类型变量需要是Person
或Person
的超类型。 A similar process for α <: γ
would yield {α <: Person}
(if the return type is specified).类似的过程
α <: γ
将产生{α <: Person}
(如果指定了返回类型)。 So we have two constraints:所以我们有两个约束:
α
needs to be Person
or a supertype of Person
; α
需要是Person
或Person
的超类型;α
needs to be Person
or a subtype of Person
; α
需要是Person
或Person
的子类型; Clearly the only type that satisfies all these constraints is Person
.显然,满足所有这些约束的唯一类型是
Person
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.