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

为什么带有绑定的泛型方法可以返回任何类型?

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

为什么带有绑定的泛型方法可以返回任何类型?

这实际上是合法的类型推断*。

我们可以将其简化为以下示例(Ideone):

interface Foo {    <F extends Foo> F bar();    public static void main(String[] args) {        Foo foo = null;        String baz = foo.bar();    }}

String & Foo
因为
Foo
是接口,所以允许编译器推断(无意义的,实际上是)交集类型。对于问题中的示例,
Integer &IElement
可以推断。

这是荒谬的,因为转换是不可能的。我们自己不能做这样的演员:

// won't compile because Integer is finalInteger x = (Integer & IElement) element;

类型推断基本上适用于:

  • 每个方法的类型参数的一组 推断变量
  • 一组必须遵守的 界限
  • 有时 约束 ,其被 降低 至界限。

在算法结束时,将根据绑定集将每个变量 解析 为交集类型,如果有效,则将编译调用。

该过程从8.1.3开始:

当推理开始时,通常从类型参数声明和关联的推理变量的列表中生成绑定集。这样的绑定集构造如下。对于每个 l(1≤l≤p)

P1, ...,Pp``α1, ..., αp
__

  • […]

  • 否则,对于在
    TypeBound
    中以

    T
    分隔的每种类型,界限将出现在集合[…]中。
    &

    __
    α l <: T[P1:=α1, ..., Pp:=αp]

因此,这意味着首先编译器以

F <: Foo
F
的子类型为
Foo
)的边界开始。

转到18.5.2,将考虑返回目标类型:

如果调用是多边形表达式,则[…]

R
设为的返回类型
m
T
设为调用的目标类型,然后:

  • […]

  • 否则,约束公式将

    ‹R θ → T›
    被简化并与[绑定集]合并。

约束公式

‹R θ → T›
被简化为的另一个边界
R θ <: T
,因此我们有
F <: String

稍后根据18.4解决:

[…] 为每个定义一个候选实例:

Ti``αi

  • 否则,在适当的上限处,。
    αi``U1, ..., Uk``Ti = glb(U1, ..., Uk)


边界与当前边界集合并。

α1 = T1, ..., αn = Tn

回想一下我们的范围是

F <: Foo, F <: String
glb(String, Foo)
定义为
String &Foo
。这显然是glb的合法类型,仅要求:

如果对于任何两个 不是interfaces )和,都不是的子类,反之亦然,则是编译时错误。

Vi``Vj``Vi``Vj

最后:

如果解析通过实例化实例变量成功完成,则将其替换。然后:

T1, ..., Tp``α1, ..., αp``θ'``[P1:=T1, ...,Pp:=Tp]

  • 如果不加以控制的转换是不必要的方法可应用于,然后的调用类型
    m
    是通过将获得
    θ'
    到的类型
    m

因此,

String & Foo
以的类型调用该方法
F
。我们当然可以将其分配给a
String
,因此不可能将a转换
Foo
为a
String

String
/
Integer
是最后一堂课的事实显然未被考虑。


*注意:类型 清除 与问题完全无关。

另外,尽管这也可以在Java 7上编译,但是我认为可以不必担心那里的规范是合理的。Java 7的类型推断本质上是Java
8的较不复杂的版本。出于类似原因进行编译。


作为附录,虽然很奇怪,但这可能永远不会引起尚未出现的问题。编写其返回类型仅从返回目标推断出的泛型方法几乎是没有用的,因为只能

null
从此类方法返回而无需强制转换。

例如,假设我们有一些映射类似物,它存储特定接口的子类型:

interface FooImplMap {    void put(String key, Foo value);    <F extends Foo> F get(String key);}class Bar implements Foo {}class Biz implements Foo {}

进行如下所示的错误已经完全有效:

FooImplMap m = ...;m.put("b", new Bar());Biz b = m.get("b"); // casting Bar to Biz

因此,我们也 可以 做到这一事实

Integer i = m.get("b");
并不是错误的
可能性。如果我们正在对这样的代码进行编程,那么一开始它就已经很不完善了。

通常,仅在没有理由绑定目标参数的情况下,才应仅从目标类型中推断出类型参数,例如

Collections.emptyList()
Optional.empty()

private static final Optional<?> EMPTY = new Optional<>();public static<T> Optional<T> empty() {    @SuppressWarnings("unchecked")    Optional<T> t = (Optional<T>) EMPTY;    return t;}

可以,因为

Optional.empty()
既不能产生也不能消耗
T



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

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

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