栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

使用泛型和Lambda重载方法时的方法调用不明确

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用泛型和Lambda重载方法时的方法调用不明确

如果我对JSE for Java SE
8的第15和18章的理解是正确的,那么问题的关键在于第15.12.2段中的以下引文:

某些包含隐式类型的lambda表达式(§15.27.1)或不精确的方法引用(§15.13.1)的参数表达式将被适用性测试忽略,因为在选择目标类型之前,无法确定其含义。

当Java编译器遇到诸如之类的方法调用表达式时

test(() ->"test")
,它必须搜索可将此方法调用分派到的可访问(可见)和适用(即具有匹配签名)的方法。在第一个示例中,
<T> voidtest(T)
<T> void test(Supplier<T>)
均可通过
test(() ->"test")
方法调用访问和适用。在这种情况下,当存在多个匹配方法时,编译器将尝试确定最具体的方法。现在,尽管对通用方法的确定(如 JLS
15.12.2.5
和JLS
18.5.4所述
)相当复杂,但我们可以使用15.12.2.5开头的直觉:

非正式的直觉是,如果第一种方法处理的任何调用都可以传递给另一个方法而没有编译时错误,则一个方法比另一种方法更具体。

因为对于任何有效的调用

<T> void test(Supplier<T>)
,我们可以找到的类型参数的对应的实例
T
<T> voidtest(T)
,前者比后者更具体。

现在,令人惊讶的部分是,在您的第二个示例中,两者

<T> void test(Class<T>, Supplier<T>)
<T> voidtest(Class<T>, T)
都被认为适用于方法调用
test(String.class, () ->"test")
,即使我们很清楚,后者也不应该。问题是,如上所述,在存在隐式类型的lambda的情况下,编译器的行为非常保守。特别参见JLS
18.5.1:

一组约束公式C的构造如下。

  • 要通过严格调用来测试适用性:

如果k≠n,或者存在i(1≤i≤n) 使得e_i与适用性有关 (§15.12.2.2)(…) 否则,对于所有i(1≤i≤k
),其中e_i与适用性有关,‹e_i→F_iθ›。

  • 要通过松散调用来测试适用性:

如果k≠n,则该方法不适用,并且无需进行推理。

否则,对于e_i与适用性有关的所有i(1≤i≤k),C包括‹e_i→F_iθ›。

和JLS
15.12.2.2:

除非参数表达式具有以下形式之一,否则认为它 可能适用的方法m的 适用性有关

  • 隐式类型的lambda表达式(第15.27.1节)。

因此,在方法适用性检查的上下文中,作为参数传递的隐式类型的lambda的约束不参与解决类型推断。

现在,如果我们假设这两种方法均适用,那么问题以及本例与前面的示例之间的区别是,这些方法都没有一个更具体。存在对无效

<T> voidtest(Class<T>, Supplier<T>)
但对无效的调用,
<T> void test(Class<T>, T)
反之亦然。

这也解释了为什么

test(String.class, (Supplier<String>) () ->"test");
编译,就像@Aominè在上面的评论中提到的那样。
(Supplier<String>) () ->"test")
是一个显式类型的lambda,因此被认为 与适用性有关 ,编译器能够正确推断出这些方法中只有一种适用,并且不会发生冲突。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/509289.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号