如何在Java泛型方法中正确返回泛型数组? [英] How to properly return generic array in Java generic method?

查看:182
本文介绍了如何在Java泛型方法中正确返回泛型数组?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在下面返回通用数组的泛型方法:

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()整数

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆