如何在 Java 中推断泛型类型? [英] How do generic types get inferred in Java?

查看:59
本文介绍了如何在 Java 中推断泛型类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Function.identity() 返回一个函数,Function 总是返回其输入参数(即身份函数).

The Function.identity() returns a function, Function<T, T> that always returns its input argument(i.e. identity function).

但是作为一个静态方法,当它甚至不接受任何输入时,它如何知道返回哪个具体参数来代替类型参数T?

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?

我的思维过程说明:

Map idToPerson = people.collect( Collectors.toMap( (person -> person.getID() , Function.identity() ) );

问题:那么编译器如何确定 Function.identity() 应该返回 Function<'people' 流的元素,'people' 流的元素>流尽管没有输入?

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?

根据 OpenJDK,实现是这样的:

According to the OpenJDK, the implementation is something like:

static <T> Function<T, T> identity()                                                                                                                          
{ 
    return t -> t;    
}

尝试缩小我的问题范围:
Function.identity()如何知道t->中的具体数据类型t是什么?t(顺便说一句,这是 lambda Function)是?

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?

推荐答案

Java 类型推断算法基于对推断变量约束公式的解析.在Java语言第18章中有详细描述规范.有点牵强.

The Java type inference algorithm is based on the resolution of constraint formulas on inference variables. It is described in detail in Chapter 18 of the Java Language Specification. It's a bit involved.

非正式地,对于上面的例子,推理大致如下:

Informally, for the example above the reasoning would go roughly as follows:

我们调用了 Function.identity().因为大多数类型参数被命名为 T,并且与 JLS 一致,我将使用希腊字母来表示推理变量.所以在这个初始表达式 T :: α 中.我们对 α 有什么限制?

We have an invocation of Function.<T>identity(). Because most type parameters are named T, and consistently with the JLS, I'll use Greek letters to denote inference variables. So in this initial expression T :: α. What constraints do we have on α?

Well identity() 返回一个 Function<α,α> 的实例,用作 toMap 的参数.

Well identity() returns an instance of Function<α,α> used as argument to toMap.

static <T,K,U> Collector<T,?,Map<K,U>>  toMap(Function<? super T,? extends K> keyMapper, 
   Function<? super T,? extends U> valueMapper)

所以现在我们有了约束{α:>T, α <: K}(其中 :> 表示 的超类型,反之亦然).这现在需要我们在这个表达式中推断 TK,我们将其称为 βγ>,所以:{α:>β, α <: γ}.为了避免陷入细节的困境,让我们只通过 β 来工作.

So now we have the constraints {α :> T, α <: K} (where :> means supertype of and vice-versa). This now requires us to infer T and K in this expression, which we'll refer to as β and γ, so: {α :> β, α <: γ}. To avoid getting bogged down in details, let's work through β only.

toMap 然后返回一个收集器作为 Stream.collect 的参数,它为我们提供了另一个约束源:

toMap then returns a collector as argument to Stream.collect, which provides us with another source of constraints:

collect(Collector<? super T,A,R> collector)

所以现在我们知道 {β :>T}.但是这里T也需要进行推断,所以变成了推断变量,我们有{β:>δ}.

So now we know that {β :> T}. But here T also needs to be inferred, so it becomes an inference variable, and we have {β :> δ}.

这是它开始展开的地方,因为方法collect的类型参数T引用了Stream<中的参数T..所以假设流被定义为Stream,现在我们有{δ=Person},我们可以减少如下:

This is where it starts unfolding, because the type parameter T for method collect refers to the parameter T in Stream<T>. So assuming the stream was defined as Stream<Person>, now we have {δ=Person} and we can reduce as follows:

  • {β:>δ} =>{β:>Person} (βPerson 的超类型);
  • {α:>β} =>{α:>(β:> 人)} =>{α:>Person)} (αPerson 的超类型);
  • {β :> δ} => {β :> Person} (β is a supertype of Person);
  • {α :> β} => {α :> (β :> Person)} => {α :> Person)} (α is a supertype of Person);

所以通过推理过程我们发现Function.identity的类型变量需要是PersonPerson的超类型.α <: γ 的类似过程将产生 {α <: 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. A similar process for α <: γ would yield {α <: Person} (if the return type is specified). So we have two constraints:

  • α 需要是 PersonPerson 的超类型;
  • α 需要是 PersonPerson 的子类型;
  • α needs to be Person or a supertype of Person;
  • α needs to be Person or a subtype of Person;

显然,唯一满足所有这些约束的类型是 Person.

Clearly the only type that satisfies all these constraints is Person.

这篇关于如何在 Java 中推断泛型类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆