如何在Java泛型方法中正确返回泛型数组? [英] How to properly return generic array in Java generic method?
问题描述
我在下面返回通用数组的泛型方法:
I have below generic method that returns a generic array:
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);
}
但稍后当我尝试使用以下结果获取结果数组时:
But later when I try to get the result array with:
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,我总是在运行时遇到错误:
For case 1, I always get error at runtime:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer;
任何人都可以解释为什么以及如何正确返回通用数组?谢谢。
Anybody can explain why and how to return the generic array properly? Thanks.
以下是我的理解,如果我错了请纠正我。
Below is my understanding, please correct me if I'm wrong.
正如Tim所提到的,类型擦除发生在编译时,因此在字节码中,每个T对象只是Object类型,同时,编译器会将对象的类型转换为正确。
As Tim mentioned, type erasure happened at compile time, so in bytecode, each T object is just type Object, meanwhile, compiler will add type cast from Object to T "properly".
假设T是一个整数,其中声明了T,它是对象。对于它所引用的位置,它是对T的类型转换(隐式)。
Say T is an Integer, where T is declared, it's Object. For where it's referred, it's type cast (implicitly) to T.
除了声明T []数组,它是Object [],并且引用数组的位置,它保持对象[]。没有隐式转换为T []。
EXCEPT that if T[] array is declared, it's Object[], and where the array is referred, it stays Object[]. No implicit cast to T[] happens.
推荐答案
您所看到的解释是由于称为类型擦除的东西。以下是 genericMethod()
在编译器执行类型擦除后的:
The explanation for what you are seeing is due to something called type erasure. Here is what your genericMethod()
will look like after the compiler performs type erasure:
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;
}
换句话说,此方法将返回<$ c $类型的数组C>对象。无法将 Object []
转换为 Integer []
,因为它们的类型不同。如果您希望您的方法能够动态返回所需的类型,那么您可以使用 Array.newInstance()
。这还需要传入您想要的数组类型作为输入参数:
In other words, this method will return an array of type Object
. There is no way to cast an Object[]
to an Integer[]
because they are not the same type. If you want your method to be able to dynamically return the type you want, then you can use Array.newInstance()
. This will require also passing in the type of the array you want as an input parameter:
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;
}
现在您的代码片段可以正常运行:
Now your code snippet will run without error:
LinkedList<Integer> list = new LinkedList<Integer>();
Integer[] i = genericMethod(Integer.class, list);
更新:
第二种方法 genericMethod2()
,在类型擦除后将如下所示:
Your second method, genericMethod2()
, will look like this after type erasure:
public static Object genericMethod2(List input) {
return input.get(0);
}
它将返回输入列表的第一个元素,强制转换为对象
。以下是您对该方法的使用:
It will return the first element of the input list, cast to Object
. Here is your usage of that method:
Integer j = genericMethod2(list);
编译器将尝试从 genericMethod2()$转换输出c $ c>到
整数
:
Integer j = (Integer)genericMethod2(list);
此演员表是合法的,因为每个整数
也是一个对象
,而且它在这里成功,因为你传递了一个 Integer
的集合。第二种方法与您为我们突出显示的第一种方法不同。
This cast is legal, because every Integer
is also an Object
, and furthermore it succeeds here because you passed in a collection of Integer
. This second method is not the same scenario as the first one you highlighted for us.
这篇关于如何在Java泛型方法中正确返回泛型数组?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!