虽然我正在开发涉及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()));
}
}
答案 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
。同样的想法适用于List
和toArray(..)
。使用重载的{{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?。