【问题标题】:How do generic types get inferred in Java?Java 中如何推断泛型类型?
【发布时间】:2021-03-28 16:38:55
【问题描述】:

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 -&gt; t 中的具体数据类型 t(顺便说一句,这是 lambda Function&lt;T, T&gt;)是什么?

【问题讨论】:

  • &lt;T&gt;一种参数。
  • 类型推断的主题太宽泛了。但这正是泛型的工作方式。在您使用Function.identity() 的上下文中,编译器推断方法调用的类型参数。你也可以自己指定它们并明确Function.&lt;Person&gt;identity() 或其他。
  • 编译器找出&lt;T&gt; 的唯一参数,该参数将使toMap 类型检查。
  • 感谢您的回复,所以你们说类型要么是推断的,要么我们可以指定它。根据Java Tutorial,根据Variable declarations, Assignments, Return statements, Array initializers, Method or constructor arguments, Lambda expression bodies, Conditional expressions, ?:, Cast expressions,推断类型
  • 我能知道在这种情况下,我们在这里使用哪种情况进行类型推断?

标签: java generics java-stream type-inference


【解决方案1】:

Java 类型推理算法基于约束公式推理变量的解析。在Chapter 18 of the Java Language Specification中有详细描述。有点牵强。

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

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

identity() 返回一个Function&lt;α,α&gt; 的实例,用作toMap 的参数。

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

所以现在我们有了约束{α :&gt; T, α &lt;: K}(其中:&gt; 表示超类型,反之亦然)。这现在需要我们在这个表达式中推断出TK,我们将它们称为βγ,所以:{α :&gt; β, α &lt;: γ}。为避免在细节方面陷入困境,让我们仅通过 β 工作。

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

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

所以现在我们知道{β :&gt; T}。但是这里T也需要推理,所以就变成了推理变量,我们就有{β :&gt; δ}

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

  • {β :&gt; δ} =&gt; {β :&gt; Person}βPerson 的超类型);
  • {α :&gt; β} =&gt; {α :&gt; (β :&gt; Person)} =&gt; {α :&gt; Person)}αPerson 的超类型);

所以通过推理过程我们发现Function.identity 的类型变量需要是PersonPerson 的超类型。 α &lt;: γ 的类似过程将产生 {α &lt;: Person}(如果指定了返回类型)。所以我们有两个约束:

  • α 需要是 PersonPerson 的超类型;
  • α 必须是 PersonPerson 的子类型;

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多