如何在Javagenerics方法中正确返回generics数组?

我有以下generics方法返回一个通用数组:

public static  T[] genericMethod1(List input) { T[] res = (T[]) new Object[input.size()]; int i = 0; for (T t : input) { res[i] = t; i++; } return res; } public static  T genericMethod2(List input) { return input.get(0); } 

但后来当我尝试使用以下结果获取结果数组时:

 LinkedList list = new LinkedList(); list.addFirst(1); list.addFirst(1); Integer[] i = (Integer[]) genericMethod1(list); // 1) Runtime error Integer j = genericMethod2(list); // 2) works 

对于案例1,我总是在运行时遇到错误:

 Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer; 

任何人都可以解释为什么以及如何正确返回通用数组? 谢谢。

以下是我的理解,如果我错了,请纠正我。

正如Tim所提到的,类型擦除发生在编译时,因此在字节码中,每个T对象只是Object类型,同时,编译器会将对象的类型转换为“正确”。

假设T是一个整数,其中声明了T,它是对象。 对于它所引用的位置,它是对T的类型转换(隐式)。

除了声明T []数组,它是Object [],并且引用数组的地方,它仍然是Object []。 没有隐式转换为T []。

您所看到的解释是由于称为类型擦除的东西。 以下是编译器执行类型擦除 genericMethod()外观:

 public static Object[] genericMethod(List input) { Object[] res = new Object[input.size()]; int i = 0; for (Object t : input) { res[i] = t; i++; } return res; } 

换句话说,此方法将返回Object类型的数组。 无法将Object[] Integer[]转换为Integer[]因为它们的类型不同。 如果希望您的方法能够动态返回所需的类型,则可以使用Array.newInstance() 。 这还需要传入您想要的数组类型作为输入参数:

 public static  T[] genericMethod(Class clazz, List input) { @SuppressWarnings("unchecked") T[] res = (T[]) Array.newInstance(clazz, input.size()); int i = 0; for (T t : input) { res[i] = t; i++; } return res; } 

现在,您的代码段将无错误地运行:

 LinkedList list = new LinkedList(); Integer[] i = genericMethod(Integer.class, list); 

更新:

第二种方法genericMethod2()在类型擦除后将如下所示:

 public static Object genericMethod2(List input) { return input.get(0); } 

它将返回输入列表的第一个元素,强制转换为Object 。 以下是您对该方法的使用方法:

 Integer j = genericMethod2(list); 

编译器将尝试将genericMethod2()的输出genericMethod2()Integer

 Integer j = (Integer)genericMethod2(list); 

这个转换是合法的,因为每个Integer也是一个Object ,而且它在这里成功,因为你传入了一个Integer集合。 第二种方法与您为我们突出显示的第一种方法不同。

当调用方法, genericMethod你假设它返回的是整数数组,这是不正确的。 它实际上在运行时返回Object类型的数组。

  List input = new ArrayList(); input.add(1); Object[] output = genericMethod(input); for(Object obj : output){ System.out.println("Value= "+ (Integer)obj); } 

所以我们需要转换数组的各个内容。

一般的指导原则是我们不应该在Java中混合使用ARRAY和GENERICS。

更新:

Effective Java的参考:

在摘要中,数组和generics具有非常不同的类型规则。 数组是协变的和具体化的; generics是不变的和擦除的。 作为一个结论,数组提供运行时类型安全性,但不提供编译时类型安全性,反之亦然。 一般来说,数组和generics不能很好地混合。 如果你发现自己混合它们并得到编译时错误或警告,你的第一个冲动应该是用列表替换数组。

另一种方法是在java.util.ArrayList.toArray(T[]) 。 您将Array的类型传递给该Method,如果它足够大则会重复使用,否则会生成一个新的Array。

例:

  List intList = new ArrayList<>(); intList.add(Integer.valueOf(1)); intList.add(Integer.valueOf(2)); intList.add(Integer.valueOf(3)); Integer[] array = intList.toArray(new Integer[] {}); System.out.println(Arrays.toString(array));//Will Print [1, 2, 3] 

ArrayList.toArray(T[])见这里 。