java中泛型类型是如何推断出来的?

njthzxwz  于 2021-06-29  发布在  Java
关注(0)|答案(1)|浏览(375)

这个 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() 知道具体的数据类型 tt -> t (顺便说一句,这是lambda Function<T, T> )是吗?

i2byvkas

i2byvkas1#

java类型的推理算法是基于推理变量上约束公式的解析。java语言规范的第18章对此进行了详细描述。有点牵扯。
非正式地说,上述例子的推理大致如下:
我们有一个 Function.<T>identity() . 因为大多数类型参数都被命名为 T ,与jls一致,我将使用希腊字母表示推理变量。在这个初始表达式中 T :: α . 我们有什么限制 α ?
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)

所以现在我们有了约束条件 {α :> T, α <: K} (其中 :> 表示的超类型,反之亦然)。现在需要我们推断 T 以及 K 在这个表达式中,我们称之为 β 以及 γ ,所以: {α :> β, α <: γ} . 为了避免陷入细节的泥沼,让我们一起努力 β 只是。 toMap 然后将收集器作为参数返回给 Stream.collect ,这为我们提供了另一个约束来源:

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

所以现在我们知道了 {β :> T} . 但是在这里 T 也需要推断,所以它变成了一个推断变量,我们有 {β :> δ} .
这就是它开始展开的地方,因为类型参数 T for方法 collect 指参数 TStream<T> . 假设流被定义为 Stream<Person> ,现在我们有了 {δ=Person} 我们可以减少如下: {β :> δ} => {β :> Person} ( βPerson ); {α :> β} => {α :> (β :> Person)} => {α :> Person)} ( αPerson );
所以通过推理的过程我们发现 Function.identity 必须是 Person 或者是 Person . 类似的过程 α <: γ 会屈服的 {α <: Person} (如果指定了返回类型)。所以我们有两个限制: α 必须是 Person 或者是 Person ; α 必须是 Person 或者是 Person ;
显然,满足所有这些约束的唯一类型是 Person .

相关问题