Java 将通用列表转换为数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6522284/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 06:36:57  来源:igfitidea点击:

Convert a generic list to an array

javagenerics

提问by Freewind

I have searched for this, but unfortunately, I don't get the correct answer.

我已经搜索过这个,但不幸的是,我没有得到正确的答案。

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;
    }
}

Test it:

测试一下:

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

But there is an error thrown:

但是抛出了一个错误:

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

How to solve this?

如何解决这个问题?



UPDATE

更新

I want this method, because sometimes, the type in my code is too long:

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

newEntries.toArray(new IClasspathEntry[0])

I'd hope to call:

我希望打电话给:

toArray(newEntries)


FINALLY

最后

It seems impossible to create such a method, thank you all very much!

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

采纳答案by Reverend Gonzo

You can just call list.toArray(T[] array)and not have to worry about implementing it yourself, but as aioobe said, you can't create an array of a generic type due to type erasure. If you need that type back, you need to create a typed instance yourself and pass it in.

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

回答by aioobe

This is due to type erasure. The generics are removed in compilation, thus the Helper.toArraywill be compiled into returning an Object[].

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

For this particular case, I suggest you use List.toArray(T[]).

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

String[] array = list.toArray(new String[list.size()]);

回答by Martijn Courteaux

String[] array = list.toArray(new String[0]);

回答by Buhake Sindi

You can't instantiate a Generic type like you did here:

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

 T[] array = (T[]) new Object[list.size()];

As, if Tis bounded to a type, you're typecasting the new Objectarray to a bounded type T. I would suggest using List.toArray(T[])method instead.

因为,如果T被限制到一个类型,你将新Object数组类型转换为一个有界类型T。我建议改用List.toArray(T[])方法。

回答by Atreys

If you want to produce your method through brute force, and you can guarantee that you'll only call the method with certain restrictions, you can use reflection:

如果你想通过蛮力产生你的方法,并且你可以保证你只会调用有一定限制的方法,你可以使用反射:

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;
}

This approach has problems. As list can store subtypes of T, treating the first element of the list as the representative type will produce a casting exception if your first element is a subtype. This means that T can't be an interface. Also, if your list is empty, you'll get an index out of bounds exception.

这种方法有问题。由于列表可以存储 T 的子类型,如果您的第一个元素是子类型,则将列表的第一个元素视为代表类型将产生强制转换异常。这意味着 T 不能是接口。此外,如果您的列表为空,您将得到一个索引越界异常。

This should only be used if you only plan to call the method where the first element of the list matches the Generic type of the list. Using the provided toArray method is much more robust, as the argument provided tells what type of array you want returned.

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

回答by P. Cédric

The problem is the component type of the array that is not String.

问题是数组的组件类型不是字符串。

Also, it would be better to not provide an empty array such as new IClasspathEntry[0]. I think it is better to gives an array with the correct length (otherwise a new one will be created by List#toArray which is a waste of performance).

此外,最好不要提供空数组,例如 new IClasspathEntry[0]。我认为最好给出一个长度正确的数组(否则 List#toArray 会创建一个新的数组,这会浪费性能)。

Because of type erasure, a solution is to give the component type of the array.

由于类型擦除,解决方案是给出数组的组件类型。

Example:

例子:

public static <C, T extends C> C[] toArray(Class<C> componentType, List<T> list) {
    @SuppressWarnings("unchecked")
    C[] array = (C[])Array.newInstance(componentType, list.size());
    return list.toArray(array);
}

The type C in this implementation is to allow creation of an array with a component type that is a super type of the list element types.

此实现中的类型 C 允许创建具有组件类型的数组,该组件类型是列表元素类型的超类型。

Usage:

用法:

public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("abc");

    // String[] array = list.toArray(new String[list.size()]); // Usual version
    String[] array = toArray(String.class, list); // Short version
    System.out.println(array);

    CharSequence[] seqArray = toArray(CharSequence.class, list);
    System.out.println(seqArray);

    Integer[] seqArray = toArray(Integer.class, list); // DO NOT COMPILE, NICE !
}

Waiting for reified generics..

等待具体化的泛型..

回答by marcolopes

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());
}

回答by Albus Dumbledore

As pointed earlier this will work:

如前所述,这将起作用:

String[] array = list.toArray(new String[0]);

And this will also work:

这也将起作用:

String[] array = list.toArray(new String[list.size()]);

However, in the first case a new array will be generated. You can see how this is implemented in Android:

但是,在第一种情况下,将生成一个新数组。您可以看到这是如何在 Android 中实现的

@Override public <T> T[] toArray(T[] contents) {
    int s = size;
    if (contents.length < s) {
        @SuppressWarnings("unchecked") T[] newArray
            = (T[]) Array.newInstance(contents.getClass().getComponentType(), s);
        contents = newArray;
    }
    System.arraycopy(this.array, 0, contents, 0, s);
    if (contents.length > s) {
        contents[s] = null;
    }
    return contents;
}

回答by Sergey Shustikov

Worked solution!

有效的解决方案!

Just copy interface and class inside your project. This :

只需在您的项目中复制接口和类。这个 :

public interface LayerDataTransformer<F, T> {
    T transform(F from);

    Collection<T> transform(Collection<F> from);

    T[] toArray(Collection<F> from);
}

and this :

和这个 :

public abstract class BaseDataLayerTransformer<F, T> implements LayerDataTransformer<F, T> {

    @Override
    public List<T> transform(Collection<F> from) {
        List<T> transformed = new ArrayList<>(from.size());

        for (F fromObject : from) {
            transformed.add(transform(fromObject));
        }

        return transformed;
    }

    @Override
    public T[] toArray(Collection<F> from) {
        Class<T> clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        T[] transformedArray = (T[]) java.lang.reflect.Array.newInstance(clazz, from.size());

        int index = 0;
        for (F fromObject : from) {
            transformedArray[index] = transform(fromObject);
            index++;
        }

        return transformedArray;
    }
}

Usage.

用法。

Declare a subclass of BaseDataLayerTransformer

声明一个 BaseDataLayerTransformer 的子类

public class FileToStringTransformer extends BaseDataLayerTransformer<File,String> {
    @Override
    public String transform(File file) {
        return file.getAbsolutePath();
    }
}

And use :

并使用:

FileToStringTransformer transformer = new FileToStringTransformer();
List<File> files = getFilesStub();// returns List<File>
//profit!
String[] filePathArray = transformer.toArray(files);

回答by tkruse

See Guava's Iterables.toArray(list, class).

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

Example:

例子:

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