我下面有返回通用数组的通用方法:
public static <T> T[] genericMethod1(List<T> input) { T[] res = (T[]) new Object[input.size()]; int i = 0; for (T t : input) { res[i] = t; i++; } return res; } public static <T> T genericMethod2(List<T> input) { return input.get(0); }
但是稍后,当我尝试使用以下方法获取结果数组时:
LinkedList<Integer> list = new LinkedList<Integer>(); 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类型,同时,编译器将“适当地”将Object的类型强制转换为T。 假设T是一个整数,其中T被声明为对象。对于引用位置,将其类型转换(隐式)为T。 除非声明了T []数组,否则为Object [],并且在引用该数组的位置保留为Object []。没有隐式转换为T []。
以下是我的理解,如果我写错了,请纠正我。
正如Tim所提到的,类型擦除是在编译时发生的,因此在字节码中,每个T对象只是Object类型,同时,编译器将“适当地”将Object的类型强制转换为T。
假设T是一个整数,其中T被声明为对象。对于引用位置,将其类型转换(隐式)为T。
除非声明了T []数组,否则为Object [],并且在引用该数组的位置保留为Object []。没有隐式转换为T []。
您看到的内容的解释是由于 类型擦除引起的 。这是编译器执行类型擦除 后 的genericMethod()样子: __
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; }
换句话说,此方法将返回type数组Object。无法将an转换Object[]为an,Integer[]因为它们不是同一类型。如果希望方法能够动态返回所需的类型,则可以使用Array.newInstance()。这还需要传入想要的数组类型作为输入参数:
Object
Object[]
Integer[]
Array.newInstance()
public static <T> T[] genericMethod(Class<T> clazz, List<T> 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<Integer> list = new LinkedList<Integer>(); Integer[] i = genericMethod(Integer.class, list);
更新:
genericMethod2()类型擦除后,您的第二种方法如下所示:
genericMethod2()
public static Object genericMethod2(List input) { return input.get(0); }
它将返回输入列表的第一个元素,强制转换为Object。这是该方法的用法:
Integer j = genericMethod2(list);
编译器将尝试将输出强制转换genericMethod2()为Integer:
Integer
Integer j = (Integer)genericMethod2(list);
此强制转换是合法的,因为所有人Integer也都是Object,并且在这里成功,因为您传入了的集合Integer。第二种方法与您为我们强调的第一种方法不同。