为什么新的Java 8流在toArray调用上返回一个Object Array?

时间:2014-10-30 21:12:45

标签: java java-8

虽然我正在开发涉及Java 8新流的项目,但我注意到当我在流上调用Stream#toArray()时,它会返回Object[]而不是T[]。我很惊讶,我开始深入研究Java 8的源代码,但没有找到任何理由说明为什么他们没有将Object[] toArray();实现为T[] toArray();。这背后有什么理由,还是只是一致性?

编辑1: 我在答案中注意到很多人说这是不可能的,但是这段代码片段会编译并返回预期的结果?

import java.util.Arrays;

public class Test<R> {

    private Object[] items;

    public Test(R[] items) {
        this.items = items;
    }

    public R[] toArray() {
        return (R[]) items;
    }

    public static void main(String[] args) {
        Test<Integer> integerTest = new Test<>(new Integer[]{
            1, 2, 3, 4
        });

        System.out.println(Arrays.toString(integerTest.toArray()));
    }

}

3 个答案:

答案 0 :(得分:21)

尝试:

String[] = IntStream.range(0, 10).mapToObj(Object::toString).toArray(String[]::new);

no-arg toArray()方法只返回一个Object [],但是如果你传递一个数组工厂(可以方便地表示为数组构造函数引用),你可以得到你喜欢的任何(兼容)类型。

答案 1 :(得分:9)

这与List#toArray()有同样的问题。类型擦除阻止我们知道应返回的数组类型。请考虑以下

class Custom<T> {
    private T t;
    public Custom (T t) {this.t = t;}
    public T[] toArray() {return (T[]) new Object[] {t};} // if not Object[], what type?
}

Custom<String> custom = new Custom("hey");
String[] arr = custom.toArray(); // fails

Object[] a String[],因此无论演员身份如何,都无法分配给Stream。同样的想法适用于ListtoArray(..)。使用重载的{{1}}方法。

答案 2 :(得分:5)

关于toArray()返回Object[]的原因:这是因为类型擦除。通用类型在运行时丢失其类型参数,因此Stream<Integer>Stream<String>Stream成为相同的类型。因此,无法确定要创建的数组的组件类型。实际上,人们可以使用反射来分析数组元素的类型,然后尝试找到他们的least upper bound,但这太复杂而且很慢。

有一种方法可以通过使用重载的toArray(IntFunction<A[]> generator)方法获取R[]数组。此方法为调用者提供了选择数组类型的机会。有关代码示例,请参阅此SO问题:How to Convert a Java 8 Stream to an Array?