将通用列表转换为数组

Fre*_*ind 62 java generics

我已经搜索过这个,但遗憾的是,我没有得到正确答案.

class Helper {
    public static <T> T[] toArray(List<T> list) {
        T[] array = (T[]) new Object[list.size()];
        for (int i = 0; i < list.size(); i++) {
            array[i] = list.get(i);
        }
        return array;
    }
}
Run Code Online (Sandbox Code Playgroud)

测试一下:

public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("abc");
    String[] array = toArray(list);
    System.out.println(array);
}
Run Code Online (Sandbox Code Playgroud)

但是抛出了一个错误:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
at test.Helper.main(Helper.java:30)
Run Code Online (Sandbox Code Playgroud)

怎么解决这个?


UPDATE

我想要这种方法,因为有时候,我的代码中的类型太长了:

newEntries.toArray(new IClasspathEntry[0])
Run Code Online (Sandbox Code Playgroud)

我希望打电话给:

toArray(newEntries)
Run Code Online (Sandbox Code Playgroud)

最后

创建这样的方法似乎是不可能的,非常感谢你们!

aio*_*obe 43

这是由于类型擦除.在编译中删除泛型,因此Helper.toArray将编译为返回a Object[].

对于这种特殊情况,我建议你使用List.toArray(T[]).

String[] array = list.toArray(new String[list.size()]);
Run Code Online (Sandbox Code Playgroud)

  • 不是应该是 `String[] array = list.toArray(new String[0]);` 吗? (2认同)

Rev*_*nzo 37

您可以调用list.toArray(T[] array)而不必担心自己实现它,但正如aioobe所说,由于类型擦除,您无法创建泛型类型的数组.如果您需要返回该类型,则需要自己创建一个类型化实例并将其传入.

  • 要实现这一点,你必须创建像`T [] array = new T [list.size()];`这样的数组,但在java中它是不可能的. (10认同)
  • 明显的警告是您需要一个类型为 T 的数组。这取决于上下文可能有问题也可能没有问题。 (2认同)
  • 编写一个名为toArray的本地方法,并在其中执行newEntries.toArray(new IClasspathEntry [0]) (2认同)

Atr*_*eys 19

如果你想通过暴力生成你的方法,并且你可以保证你只能用某些限制来调用方法,你可以使用反射:

public static <T> T[] toArray(List<T> list) {
    T[] toR = (T[]) java.lang.reflect.Array.newInstance(list.get(0)
                                           .getClass(), list.size());
    for (int i = 0; i < list.size(); i++) {
        toR[i] = list.get(i);
    }
    return toR;
}
Run Code Online (Sandbox Code Playgroud)

这种方法存在问题.由于列表可以存储T的子类型,因此如果第一个元素是子类型,则将列表的第一个元素视为代表类型将产生转换异常.这意味着T不能是一个接口.此外,如果您的列表为空,您将获得索引超出范围的异常.

仅当您计划调用列表的第一个元素与列表的通用类型匹配的方法时,才应使用此方法.使用提供的toArray方法更加健壮,因为提供的参数告诉您要返回的数组类型.

  • 但这让我觉得很脏. (11认同)
  • 另外,如果第一个元素为null,则会得到空指针异常 (2认同)
  • 我同意它很脏,但我想这是在编译时不知道它的类型而创建这样一个数组的唯一方法.至少"第一个元素是子类型"问题可以通过迭代列表中的所有元素并寻找最具体的常见超类型来解决.如果所有元素都扩展了一些'T`的子类型,从例如`Integer []`到`Number []`是可能的,那么这也会有效.其他问题(列表为空或仅包含`null`值,并且`T`不能是接口,除非公共超类型实现它的元素)仍然存在. (2认同)

Buh*_*ndi 9

您不能像在此处那样实例化Generic类型:

 T[] array = (T[]) new Object[list.size()];
Run Code Online (Sandbox Code Playgroud)

因为,如果T绑定到某个类型,则将新Object数组类型转换为有界类型T.我建议改用List.toArray(T[])方法.


tkr*_*use 8

见番石榴Iterables.toArray(list, class).

例:

@Test
public void arrayTest() {
    List<String> source = Arrays.asList("foo", "bar");
    String[] target = Iterables.toArray(source, String.class);
}
Run Code Online (Sandbox Code Playgroud)


Mar*_*aux 5

String[] array = list.toArray(new String[0]);
Run Code Online (Sandbox Code Playgroud)

  • 这提出了一个重点。`toArray`的参数不必与返回的数组大小相同!它只能用于指定类型! (2认同)

mar*_*pes 5

public static <T> T[] toArray(Collection<T> c, T[] a) {
    return c.size()>a.length ?
        c.toArray((T[])Array.newInstance(a.getClass().getComponentType(), c.size())) :
        c.toArray(a);
}

/** The collection CAN be empty */
public static <T> T[] toArray(Collection<T> c, Class klass) {
    return toArray(c, (T[])Array.newInstance(klass, c.size()));
}

/** The collection CANNOT be empty! */
public static <T> T[] toArray(Collection<T> c) {
    return toArray(c, c.iterator().next().getClass());
}
Run Code Online (Sandbox Code Playgroud)