【问题标题】:Strange type inference behavior of Collections.emptyList() and/or Java generic methods?Collections.emptyList() 和/或 Java 泛型方法的奇怪类型推断行为?
【发布时间】:2012-05-07 17:49:03
【问题描述】:

这是jdk1.7.0_04

我试图使用 Collections.emptyList() 而不是 new 在条件中添加我自己的空列表:

List<String> list = (anArray != null) ? Arrays.asList(anArray) : Collections.emptyList();

但得到以下错误:

error: incompatible types
        List<String> list = (anArray != null) ? Arrays.asList(anArray) : Collections.emptyList();
                                              ^
  required: List<String>
  found:    List<CAP#1>
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ? extends Object
1 error

我能够确定我需要将事情更改为:

List<String> list = (anArray != null) ? Arrays.asList(anArray) : Collections.<String>emptyList();

但作为工作的一部分,我遇到了奇怪的(对我来说,无论如何)情况:

List<String> alwaysEmpty = Collections.emptyList();

编译正常,但是:

List<String> alwaysEmpty = (List<String>) Collections.emptyList();

给出以下编译错误:

error: inconvertible types
        List<String> alwaysEmpty = (List<String>) Collections.emptyList();
                                                                       ^
  required: List<String>
  found:    List<Object>

什么鬼??

现在我可以理解,也许由于某种奇怪的原因,条件运算符的使用会以某种方式阻止类型推断系统意识到emptyList() 调用的类型参数应该是String,因此需要明确指定的。但是为什么插入一个(诚然是多余的)演员会搞砸呢?

【问题讨论】:

    标签: java generics collections


    【解决方案1】:

    但是为什么插入一个(诚然是多余的)演员表会搞砸呢?

    因为现在表达式 Collections.emptyList() 本身不是任何赋值的目标 - 那么应该选择什么类型的参数呢?最好只指定类型参数:

    // Redundant here, but just as an example
    List<String> alwaysEmpty = Collections.<String>emptyList();
    

    条件运算符也一样:

    public static void main(String[] args) {              
        List<String> list = (args != null)
            ? Arrays.asList(args) : Collections.<String>emptyList();
    }
    

    【讨论】:

      【解决方案2】:

      我将接受 Jon 的回答,但也想列出某人刚刚向我传递的关于 SO 之外的内容。这是一个链接到 bug report 提交给 Sun/Oracle 的关于这件事的链接。评估错误的人对正在发生的事情有一个有用的解释。摘录:

      这里的提交者似乎假设条件表达式的类型是分配的 LHS 上的类型(在这种情况下为List&lt;String&gt;)。这不是真的:正如 JLS 所述,条件表达式的类型:

      “条件表达式的类型是对lub(T1, T2)(§15.12.2.7)应用捕获转换(§5.1.10)的结果。”

      了解为什么需要使用 lub 非常重要。考虑以下示例:

      class A {}
      class B extends A{}
      class C extends A{}
      class Foo<X> 
      Foo<? extends A> l = b ? new Foo<B>() : new Foo<C>()
      

      在这种情况下,LHS 的类型为 Foo&lt;? extends A&gt;,而 RHS 的类型为 lub(Foo&lt;B&gt;, Foo&lt;C&gt;),即Foo&lt;? extends B&amp;C&gt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多