一尘不染

如何在Java通用方法中正确返回通用数组?

java

我下面有返回通用数组的通用方法:

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 []。


阅读 303

收藏
2020-12-03

共1个答案

一尘不染

您看到的内容的解释是由于 类型擦除引起的 。这是编译器执行类型擦除 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()。这还需要传入想要的数组类型作为输入参数:

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()类型擦除后,您的第二种方法如下所示:

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

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

Integer j = genericMethod2(list);

编译器将尝试将输出强制转换genericMethod2()Integer

Integer j = (Integer)genericMethod2(list);

此强制转换是合法的,因为所有人Integer也都是Object,并且在这里成功,因为您传入了的集合Integer。第二种方法与您为我们强调的第一种方法不同。

2020-12-03