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

泛型是如何工作的?

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

泛型是如何工作的?

正如肯尼(Kenny)在评论中指出的那样,您可以通过以下方法解决此问题:

List<Test<? extends Number>> l =    Collections.<Test<? extends Number>>singletonList(t);

这立即告诉我们,该操作并非 不安全 ,只是 推理 受限的受害者。如果不安全,则以上内容将无法编译。

由于仅在上述通用方法中使用显式类型参数才有必要充当 提示 ,因此我们可以推测,此处所要求的显式类型参数是推理引擎的技术限制。实际上,Java
8编译器目前预计将对类型推断进行许多改进。我不确定您的具体情况是否会解决。

那么,实际发生了什么?

那么,编译错误我们得到节目类型参数

T
Collections.singletonList
被推断为
capture<Test<? extendsNumber>>
。换句话说,通配符具有一些与之关联的元数据,可将其链接到特定的上下文。

  • 想到捕获通配符(
    capture<? extends Foo>
    )的最佳方法是将其作为具有相同界限的 未命名 类型参数(即
    <T extends Foo>
    ,但无法引用
    T
    )。
  • “释放”捕获功能的最佳方法是将其绑定到通用方法的命名类型参数。我将在下面的示例中对此进行演示。有关更多信息,请参见Java教程“通配符捕获和帮助程序方法”(感谢@WChargin的引用)。

假设我们要有一个移动列表的方法,将其包装在后面。然后,假设我们的列表具有未知(通配符)类型。

public static void main(String... args) {    List<? extends String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));    List<? extends String> cycledTwice = cycle(cycle(list));}public static <T> List<T> cycle(List<T> list) {    list.add(list.remove(0));    return list;}

这可以正常工作,因为

T
解决了
capture<? extends String>
,而不是
? extendsString
。如果我们改为使用以下非通用实现循环:

public static List<? extends String> cycle(List<? extends String> list) {    list.add(list.remove(0));    return list;}

它将无法编译,因为我们尚未通过将捕获分配给类型参数来使其可访问。

因此,这开始解释了为什么of的使用者

singletonList
将从类型推断器解析
T
为中受益
Test<capture<? extendsNumber>
,并因此返回a
List<Test<capture<? extends Number>>>
而不是a
List<Test<?extends Number>>

但是为什么不能将一个分配给另一个呢?

为什么我们不能仅将a分配

List<Test<capture<? extends Number>>>
List<Test<? extendsNumber>>

好吧,如果我们考虑到

capture<? extendsNumber>
一个匿名类型参数的上限等于的事实
Number
,那么我们可以将这个问题变成“为什么下面的代码不编译?” (不是!):

public static <T extends Number> List<Test<? extends Number>> assign(List<Test<T>> t) {    return t;}

这有一个不编译的充分理由。如果确实如此,那么这将是可能的:

//all this would be validList<Test<Double>> doubleTests = null;List<Test<? extends Number>> numberTests = assign(doubleTests);Test<Integer> integerTest = null;numberTests.add(integerTest); //type error, now doubleTests contains a Test<Integer>

那么为什么显式工作呢?

让我们回到起点。如果以上内容不安全,则允许这样做:

List<Test<? extends Number>> l =    Collections.<Test<? extends Number>>singletonList(t);

为此,它意味着允许以下操作:

Test<capture<? extends Number>> capturedT;Test<? extends Number> t = capturedT;

嗯,这不是有效的语法,因为我们无法显式引用捕获,因此让我们使用与上述相同的技术对其进行评估!让我们将捕获绑定到“ assign”的另一个变体上:

public static <T extends Number> Test<? extends Number> assign(Test<T> t) {    return t;}

这样编译成功。不难看出为什么它应该是安全的。这是类似

List<? extends Number> l = new List<Double>();


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

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

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