我正在尝试构建一个帮助方法,将两个行列表转换为数组转换为一行.我遇到的问题是我不确定如何创建一个T []实例.
我试过了
Array.newInstance(T.class, list.size) 但我无法喂它T.class ..
也试过,new T[](list.size)但它不喜欢参数.
public <T> T[] ConvertToArray(List<T> list)
{
T[] result = ???
result = list.toArray(result);
return result;
}
Run Code Online (Sandbox Code Playgroud)
还有其他想法吗?
谢谢
ZoF*_*reX 14
你不能混淆泛型和那样的数组.泛型具有编译时检查,数组具有运行时检查,并且这些方法大多不兼容.起初我建议:
@SuppressWarnings("unchecked")
public <T> T[] ConvertToArray(List<T> list)
{
Object[] result = new Object[list.size()];
result = list.toArray(result);
return (T[])result;
}
Run Code Online (Sandbox Code Playgroud)
这是一种隐秘的错误,因为至少有一个其他人认为它会起作用!但是,当您运行它时会出现不兼容的类型错误,因为您无法将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;
}
Run Code Online (Sandbox Code Playgroud)
请注意,我们有第二个参数在运行时(以及通过泛型编译时)提供类.你会像这样使用它:
Integer[] arrayOfIntegers = convertToArray(listOfIntegers, Integer.class);
Run Code Online (Sandbox Code Playgroud)
这值得麻烦吗?我们仍然需要压制警告,所以它绝对安全吗?
我的回答是肯定的.生成的警告只是来自编译器的"我不确定".通过单步执行,我们可以确认该转换将始终成功 - 即使您将错误的类作为第二个参数,也会抛出编译时警告.
这样做的主要优点是我们已将警告集中到一个地方.我们只需要证明这一个地方是正确的,我们知道代码将永远成功.引用Java文档:
该语言旨在保证如果您的整个应用程序使用javac -source 1.5编译时没有未经检查的警告,则它是类型安全的[1]
所以现在不是在你的代码中都有这些警告,而是只在一个地方,你可以使用它而不必担心 - 通过使用它可以大大降低你犯错误的风险.
您可能还想看看这个SO答案,它更深入地解释了这个问题,这个答案是我写这篇文章时的床单.除了已经引用的Java文档之外,我使用的另一个方便的参考是Neal Gafter的博客文章,他是Sun Microsystems的高级工程师,以及1.4和5.0语言功能的共同设计师.
当然,感谢ShaneC正确地指出我的第一个答案在运行时失败了!
| 归档时间: |
|
| 查看次数: |
11853 次 |
| 最近记录: |