未经检查的转换:'java.lang.Object[]' 到 'T[]'

lsi*_*iem 3 java generics

我有以下方法:

public static <T> T[] toArray(Iterable<? extends T> iterable) {
  return (T[]) StreamSupport.stream(iterable.spliterator(), false).toArray();
}
Run Code Online (Sandbox Code Playgroud)

我的 IDE 告诉我存在未经检查的强制转换。一般来说,我理解错误消息,但我无法理解为什么应该检查强制转换,因为 iterable 具有与我用于强制转换的相同类型。有人可以向我解释一下吗?

And*_*ner 6

但我不明白为什么要检查演员阵容

经过检查的强制转换会产生checkcast字节码指令。例如:

String s = (String) someObject;
Run Code Online (Sandbox Code Playgroud)

在泛型的情况下,checkcast无法插入指令,因为代码中的该点没有已知的类型:a检查的类型checkcast被静态写入字节码;但你的方法必须适用于所有类型。因此,checkcast这里不能添加任何内容。

警告是编译器表达“我不能确定,但​​这里看起来有点可疑”的方式。事实上,确实有一些可疑的地方,但问题并没有出现在这段代码中。

假设您将此方法称为如下:

Integer[] ints = toArray(iterableOfInts);
Run Code Online (Sandbox Code Playgroud)

实际上会在调用站点插入经过检查的强制转换(由编译器插入):

Integer[] ints = (Integer[]) toArray(iterableOfInts);
Run Code Online (Sandbox Code Playgroud)

这将在运行时失败,因为Object[]无法转换为Integer[]. 但失败发生在这里,而不是toArray方法上。

解决这个问题的正确方法是提供一些东西来创建T[]

public static <T> T[] toArray(Iterable<? extends T> iterable, IntFunction<T[]> arraySupplier) {
  return StreamSupport.stream(iterable.spliterator(), false).toArray(arraySupplier);
}
Run Code Online (Sandbox Code Playgroud)

Iterable<? extends T>是一个合适的参数类型,因为它允许您创建超类型的数组:

Integer[] integers = toArray(iterableOfInts, Integer[]::new);
Object[] objects = toArray(iterableOfInts, Object[]::new);
Run Code Online (Sandbox Code Playgroud)