【问题标题】:Odd generics behaviour of List.toArray(T[])List.toArray(T[]) 的奇怪泛型行为
【发布时间】:2010-11-07 14:38:36
【问题描述】:

我今天遇到了一些非常基本但非常令人困惑的事情。我需要将列表转换为数组。该列表包含String 实例。使用List.toArray(T[]) 的完美示例,因为我想要一个String[] 实例。但是,如果不将结果显式转换为 String[],它将无法工作。

作为测试场景,我使用了以下代码:

import java.util.Arrays;
import java.util.List;

public class MainClass {
    public static void main(String args[]) {
        List l = Arrays.asList("a", "b", "c");
        String stuff[] = l.toArray(new String[0]);
        System.err.println(Arrays.asList(stuff));
    }
}

不编译。它几乎是 javadoc 中示例的精确副本,但编译器显示以下内容:

MainClass.java:7: incompatible types
found   : java.lang.Object[]
required: java.lang.String[]
    String stuff[] = l.toArray(new String[0]);
                          ^

如果我向String[] 添加演员表,它将完美编译并运行。但是当我查看 toArray 方法的签名时,这并不是我所期望的:

<T> T[] toArray(T[] a)

这告诉我我不应该施放。怎么回事?

编辑:

奇怪的是,如果我将列表声明更改为:

List<?> l = Arrays.asList("a", "b", "c");

它也有效。或List&lt;Object&gt;。所以它不必像建议的那样是List&lt;String&gt;。我开始认为使用原始的List 类型也会改变该类中泛型方法的工作方式。

第二次编辑:

我想我现在明白了。 Tom Hawtin 在下面的评论中写的似乎是最好的解释。如果您以原始方式使用泛型类型,则该实例中的所有泛型信息都将被编译器删除。

【问题讨论】:

    标签: java arrays list


    【解决方案1】:

    您忘记为您的列表指定类型参数:

    List<String> l = Arrays.asList("a", "b", "c");
    

    在这种情况下,您可以编写安全性:

    String[] a = l.toArray(new String[0]);
    

    没有任何演员表。

    【讨论】:

    • 这在逻辑上对我来说是有道理的,但在技术上却不是。在我看来, toArray 方法并不关心 E 绑定的内容(即列表的元素类)。
    • toArray的签名为“public T[] toArray(T[] a)”,T为传入数组的组件类型
    • 我也看不懂,更糟糕的是它也可以使用 List(或 List>)作为“l”
    • 语言规范已经相当复杂了,所以与其为部分泛化代码(为什么要部分泛化代码?)提出更复杂的规则,所有泛型都被丢弃了。我相信 JDK7 有 -Xlint:rawtypes 可以捕捉到这个错误。
    • 没错。在我的示例中,T 是 String[]。因此,无论列表中有什么元素,它都应该返回 String[]。
    【解决方案2】:

    或者做

    List<?> l = Arrays.asList("a", "b", "c");  
    

    还是很奇怪

    【讨论】:

    • +1 反击。它确实解决了这个问题——我自己也注意到了同样的怪事。
    • 最差:它也使用 List 编译,但应该在运行时崩溃... :-/
    【解决方案3】:
    List<String> l = Arrays.asList("a", "b", "c");
    

    这将使它编译,您使用泛型表示“这是一个字符串列表”,因此 toArray 方法知道要返回哪种类型的数组。

    【讨论】:

      【解决方案4】:

      那是因为您的列表包含对象,而不是字符串。如果您将列表声明为 List&lt;String&gt;,编译器会很高兴。

      【讨论】:

        【解决方案5】:

        List 没有声明类型将默认为“对象列表”,而List&lt;?&gt; 表示“未知列表”。在泛型类型的世界中,“对象列表”与“字符串列表”不同是事实,但编译器不能对“未知列表”说同样的话。如果您已将其声明为未知,那么就编译器所知,没关系。

        主要的一点是,将某些东西声明为通配符?与将其声明为 Object 不同。阅读更多关于通配符here

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-10-28
          • 1970-01-01
          • 2019-05-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多