【问题标题】:Need help in understanding Java tutorial on Generics在理解泛型 Java 教程方面需要帮助
【发布时间】:2019-01-28 18:09:20
【问题描述】:

我正在阅读来自here 的 Java 教程。我无法理解一条简单的线。

教程说Collections.emptyList的声明是:

static <T> List<T> emptyList();

所以如果我们写List<String> listOne = Collections.emptyList();,它的工作原理是Java编译器能够推断类型参数,因为返回的值应该是List<String>类型。

现在考虑一个方法:void processStringList(List<String> stringList)。现在它指出:

processStringList(Collections.emptyList()); Java SE 7 编译器 生成类似于以下的错误消息:

List 无法转换为 List

编译器需要 类型参数 T 的值,因此它以值 Object 开头。 因此, Collections.emptyList 的调用返回一个值 List<Object> 类型的,与方法不兼容 进程字符串列表

现在它们是什么意思:所以它以值 Object 开头?我的意思是开始做什么?

【问题讨论】:

  • 它只是意味着它推断TObject
  • 仅供参考,它进一步解释说他们已经在 J​​ava 8 中修复了这个问题,所以除非你使用的是遗留代码,否则它基本上是无关紧要的。 processStringList(Collections.emptyList()) 很好地推断出类型。
  • @AndyTurner 是的,我说“它在 [页面] 下方进一步解释”
  • 除了前面的cmets中所说的,我想澄清一下,该行实际上被处理为List listOne = Collections.emptyList();您可以在方法名称之前添加类型参数,即使用作方法参数,它也会按照您的预期工作。
  • 感谢您的快速回归!

标签: java generics


【解决方案1】:

基本上这是关于编译器的功能。换句话说:在某种程度上,可能的类型推断的“数量”是一个实现细节。

在 Java 7 中,您有时必须使用类型助手/提示/见证,您可以在此处使用 Collections.<String>emptyList() 告诉编译器该缺失部分。

编译器的后期实现改善了您几乎总是可以使用 Collections.emptyList() 的情况。

关于The compiler requires a value for the type argument T so it starts with the value Object. ...这实际上很简单:java编译器必须实现一个算法,最后推断出一个特定的类型。给出一些伪代码,可能看起来像:

Class<?> inferType(SomeSyntaxTree construct) {

我只是在这里使用Class 表示该算法将返回类似于已知类型的东西。现在,该方法可以这样实现:

 Class<?> inferedType = Object.class
 while (whatever) {
   refine inferedType
 }
 return inferedType

换句话说:当您“搜索”某个值时,这是一种非常常见的方法:您使用“最通用”的值(在 Java 类型系统中,即 Object.class)进行初始化,然后您会看到如果可以通过应用任何算法来完善该通用值。

在我们的例子中,细化最终可能会得出“可以使用的最具体的类型是String”,但如果无法进一步细化,那么您最终会得到“初始默认值”,即@ 987654328@.

【讨论】:

  • 他们在教程中被称为类型witnesses(虽然我在JLS中找不到这个词)。
  • @AndyTurner 似曾相识。我总是忘记正确的名字。谢谢你提醒我。
  • 这是语言规范,而不仅仅是编译器的变化。 (我认为。有错误。)
【解决方案2】:

声明

processStringList(Collections.emptyList());

在 Java 8 中运行良好(我假设也高于 8)。在这种情况下,编译器足够聪明,可以通过检查方法的预期参数类型来推断类型。

在旧版本中,当编译器没有看到明确的返回类型(如List&lt;String&gt; listOne = Collections.emptyList();)时,它默认将&lt;T&gt; 推断为java.lang.Object。但请注意List&lt;Object&gt;List&lt;String&gt; 不兼容。

你可以声明void processString(List&lt;? super String&gt; list)这样的方法来避免错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-01
    • 2011-10-04
    • 2018-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多