我正在尝试构建一个帮助方法,将两行列表转换为数组转换为一行。我遇到的问题是我不确定如何创建一个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;
}
还有其他想法吗?
谢谢
你不能混合泛型和类似的数组。泛型具有编译时检查,数组具有运行时检查,并且这些方法大多不兼容。起初我建议:
@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编译整个应用程序而没有未经检查的警告,则它是类型安全的[1]
所以现在不是在你的代码中都有这些警告,它只是在一个地方,你可以使用它而不必担心 - 通过使用它可以大大降低你犯错误的风险。
你可能也想看看 这个答案 这更深入地解释了这个问题,并且 这个答案 写这篇文章时,这是我的床单。以及 已经引用了Java文档,我用的另一个方便的参考 这篇博文 作者:Sun Microsystems前高级工程师Neal Gafter,以及1.4和5.0语言功能的联合设计师。
当然,感谢ShaneC正确地指出我的第一个答案在运行时失败了!
如果你不能传入 T.class
那你基本上搞砸了。类型擦除意味着你根本不知道它的类型 T
在执行时。
当然还有其他指定类型的方法,例如 超级型代币 - 但我的猜测是,如果你不能通过 T.class
,您也无法传递类型令牌。如果可以,那就太好了:)
问题是因为类型擦除,List在运行时不知道它的组件类型,而组件类型是创建数组所需的类型。
因此,您可以在API中找到两个选项:
我能想到的唯一另一种可能性是一个巨大的麻烦:
- 迭代列表中的所有项目并找到“最大公约数”,这是所有项目扩展或实现的最具体的类或接口。
- 创建该类型的数组
但这将比你的两行更多(并且它也可能导致客户端代码做出无效的假设)。
这真的需要改成单行吗?对于任何具体类,您可以在一行中执行List to Array转换:
MyClass[] result = list.toArray(new MyClass[0]);
当然,这不适用于类中的泛型参数。
见约书亚布洛赫 有效的Java第二版,第25项:首选列表到阵列(第119-123页)。这是其中的一部分 样本章PDF。
这是我能看到的最接近你想要的东西。这使得您在编写代码时知道类的大假设以及列表中的所有对象都是同一个类,即没有子类。我确信这可以更复杂,以减轻没有子类的假设,但我不知道如何在Java中你可以绕过在编码时知道类的假设。
package play1;
import java.util.*;
public class Play
{
public static void main (String args[])
{
List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("Shalom");
list.add("Godspidanya");
ArrayTool<String> arrayTool=new ArrayTool<String>();
String[] array=arrayTool.arrayify(list);
for (int x=0;x<array.length;++x)
{
System.out.println(array[x]);
}
}
}
class ArrayTool<T>
{
public T[] arrayify(List<T> list)
{
Class clazz=list.get(0).getClass();
T[] a=(T[]) Array.newInstance(clazz, list.size());
return list.toArray(a);
}
}