Java 为什么列表<;字符串>;。toArray()返回对象[]而不是字符串[]?如何解决这个问题?

Java 为什么列表<;字符串>;。toArray()返回对象[]而不是字符串[]?如何解决这个问题?,java,generics,Java,Generics,有人知道为什么Java 1.6会有这种行为吗 List<String> list = ArrayList<String>(); String[] arr = (String[]) list.toArray(); List List=ArrayList(); String[]arr=(String[])list.toArray(); 我得到一个ClassCastException,因为它返回Object[],而不是String[] 我想 List.toArray()应返

有人知道为什么Java 1.6会有这种行为吗

List<String> list = ArrayList<String>();
String[] arr = (String[]) list.toArray();
List List=ArrayList();
String[]arr=(String[])list.toArray();
我得到一个ClassCastException,因为它返回Object[],而不是String[]

我想
List.toArray()
应返回T[]-否?有人能回答为什么语言中存在这种不便吗?
以及如何解决这个问题?如何从
列表
中获取字符串[],而不在项目中循环?

您需要传入一个数组,这样它的运行时类型可以被
toArray
用作提示。请改为尝试
toArray(新字符串[0])
。您还可以传入预先调整大小的数组

要理解,考虑什么类型的擦除会使

new T[4]
工作。如果Java允许这样做,那么它在擦除后所能做的最好的事情就是

new Object[4]

大多数
toArray
实现都使用在类型提示作为
类传递的情况下构造正确类型的输出数组,因为数组从一开始就在Java中,而泛型仅在Java 5中引入。而
List.toArray()
方法是在泛型出现之前在Java1.2中引入的,因此它被指定返回
Object[]
。许多现有代码现在都希望
List.toArray()
返回
Object[]
,因此现在无法更改它

此外,泛型在运行时会被擦除,所以
ArrayList
甚至无法构造正确类型的数组


这个方法的漏洞是,它将返回一个正确类型的数组,前提是您给它一个正确类型的数组,以便它知道使用哪种类型。

要理解为什么会发生这种情况,只需查看javadoc,然后查看该方法。还要记住,Java中的泛型在运行时会被删除。

原因有二:

  • 该方法在泛型之前,它们无法在不破坏向后兼容性的情况下更改签名

  • 在任何情况下,由于
    列表
    是在没有
    的情况下构造的,因此实现无法构造
    T
    类型的数组


  • 解决方法将使用:

           List<String> list = new ArrayList<>();
             list.add("Sputnik");
             list.add("Explorer");
    
            //String[] str = list.toArray(); 
    

    谢谢你,Mike,我没有注意到这个方法t[]toArray(t[]arg0)-它返回我需要的。或者使用
    toArray(新字符串[list.size()])
    如果你想避免分配大小为0的数组,那么下面的答案是
    list
    接口不能提供
    E[]toArray()
    方法,因为它会与旧的
    对象[]toArray()
    方法冲突,该方法在1.2中引入,并且需要向后兼容。这是有道理的,因为您不能有两个只因返回类型而异的方法签名。但是你的回答暗示
    E[]toArray()
    由于类型擦除而无法工作-我读对了吗?或者,在使用
    T
    作为泛型类型和使用
    E
    作为声明的列表界面之间是否存在细微差别?是的,我想我忽略了明显的差别。像
    E get(int index)
    这样的列表方法之所以有效,是因为它们是在编译时强制执行的,不必在运行时知道或构造类型
    E[]toArray()
    可以在运行时检查其返回值赋值/传递/等,但实际上构造数组需要了解正确的类型。Jave实际上没有
    t[]
    的概念。可能是“的重复项”,因此它被指定为返回对象[]。许多现有代码现在需要List.toArray()返回对象[],因此现在无法更改。”胡说八道。Java收集方法的返回类型已更改为泛型。这完全无关。实际原因是不同类型的数组在运行时是不同的,因此它不可能返回正确类型的数组。这在泛型前后都是正确的。丹尼尔,真的吗?这个问题已经被问过多少次了?一百万?你是在教训我回答一个重复的问题吗?@unjutable:我昨天回答这个问题时,没有立即看到(也没有立即记住)一个完全重复的问题。今天我快速搜索了一下,我想已经够近了。如果你确信一个问题是重复的,那么与其假设你不诚实,为什么不投票结束你自己呢?你有足够的代表@newacct:我不确定这是否完全无关。的确,Java5还引入了返回类型协方差,因此返回
    t[]
    而不是
    Object[]
    不一定是一个突破性的改变。但是由于数组方差的工作方式很奇怪:,返回
    T[]
    是否正确?我的一般经验法则是,您可以使用泛型,也可以使用数组协方差,但应避免同时使用这两种方法。@Daniel:返回类型协方差(处理重写方法的返回类型)在这里没有问题,因为它的所有超类(集合)中都有
    toArray()
    方法也将更改为
    T[]
    。至于你关于它是否正确的问题,假设一个方法可以神奇地返回一个T[],那么在大多数情况下它都是正确的,因为
    T[]
    Object[]
    的一个子类,所以任何想要
    Object[]
    的人都应该能够接受
    T[]
    。唯一的例外是,如果他们试图在数组中插入一个不同类型的元素,这种可能性非常罕见。您会将签名更改为什么?您的意思是返回类型T[]?如果尝试使用ClassCastException,您将得到一个ClassCastException,因为当您更改方法签名时,该方法仍然会创建一个对象[]@newacct。通常情况下,更改实现以进行匹配。但是,请看我的编辑。我的反对意见是Java api中的所有方法签名都发生了更改(例如,所有集合类的方法,
           Instead use:
    
            String[] str = list.toArray(new String[0]);
            or
            String[] str = list.toArray(new String[list.size()]);