你不能像那样混合泛型和数组。泛型有编译时检查,数组有运行时检查,这些方法大多不兼容。一开始我是这样建议的:
@SuppressWarnings("unchecked")
public <T> T[] ConvertToArray(List<T> list)
{
Object[] result = new Object[list.size()];
result = list.toArray(result);
return (T[])result;
}
这是隐秘的错误,因为至少这里的另一个人认为它会起作用!但是,当您运行它时,您会收到不兼容的类型错误,因为您不能将 Object[] 转换为 Integer[]。为什么我们不能获得 T.class 并创建一个正确类型的数组?还是new T[]?
泛型使用类型擦除来保持向后兼容性。它们在编译时进行检查,但从运行时剥离,因此字节码与预泛型 JVM 兼容。这意味着您无法在运行时获得泛型变量的类知识!
因此,尽管您可以提前保证 T[] result 的类型为 Integer[],但代码 list.toArray(result);(或 new T[],或 Array.newInstance(T.class, list.size());)只会在运行时发生,它无法知道T是什么!
这是一个确实有效的版本,作为阅读该讲座的奖励:
public static <T> T[] convertToArray(List<?> list, Class<T> c) {
@SuppressWarnings("unchecked")
T[] result = (T[]) Array.newInstance(c, list.size());
result = list.toArray(result);
return (T[]) result;
}
请注意,我们有第二个参数用于在运行时(以及在编译时通过泛型)提供类。你可以这样使用:
Integer[] arrayOfIntegers = convertToArray(listOfIntegers, Integer.class);
这值得麻烦吗?我们仍然需要抑制警告,所以它绝对安全吗?
我的答案是肯定的。那里生成的警告只是来自编译器的“我不确定”。通过单步执行,我们可以确认强制转换总是会成功 - 即使您将错误的类作为第二个参数放入,也会引发编译时警告。
这样做的主要优点是我们将警告集中到一个地方。我们只需要证明这一点是正确的,我们就知道代码总是会成功。引用 Java 文档:
该语言旨在保证如果您的整个应用程序已使用 javac -source 1.5 编译而没有未经检查的警告,则其类型为 safe[1]
因此,现在不是在您的代码中到处都是这些警告,而是在一个地方,您可以使用它而不必担心 - 使用它会大大降低您犯错的风险。
您可能还想查看this SO answer,它更深入地解释了这个问题,以及this answer,这是我写这篇文章时的婴儿床单。除了already cited Java documentation,我使用的另一个方便的参考是this blog post,Neal Gafter 是 Sun Microsystems 的前高级工程师,也是 1.4 和 5.0 语言功能的联合设计师。
当然,还要感谢 ShaneC,他正确地指出我的第一个答案在运行时失败了!