将通用列表转换为数组

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

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

testing它:

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

但是有一个错误:

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

如何解决这个问题?


UPDATE

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

 newEntries.toArray(new IClasspathEntry[0]) 

我希望打电话给:

 toArray(newEntries) 

最后

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

你可以直接调用list.toArray(T[] array) ,而不必担心自己实现它,但是按照aioobe的说法,由于types擦除,你不能创build一个genericstypes的数组。 如果你需要返回types,你需要自己创build一个types化的实例并将其传入。

这是由于types擦除。 generics在编译时被删除,因此Helper.toArray将被编译成返回一个Object[]

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

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

如果你想通过暴力来产生你的方法,你可以保证你只会调用具有一定限制的方法,你可以使用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; } 

这种方法有问题。 由于列表可以存储T的子types,因此如果您的第一个元素是子types,则将列表的第一个元素作为代表types将产生一个转换exception。 这意味着T不能成为一个接口。 另外,如果你的列表是空的,你会得到一个索引越界exception。

只有在您打算调用列表的第一个元素与列表的Generictypes相匹配的方法时,才应该使用该方法。 使用提供的toArray方法更健壮,因为提供的参数告诉你要返回的数组types。

你不能像在这里那样实例化一个genericstypes:

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

因为,如果T被绑定到一个types,你将新的Object数组types化为一个有界的typesT 我build议使用List.toArray(T[])方法。

 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()); } 
 String[] array = list.toArray(new String[0]); 

问题是不是String的数组的组件types。

另外,最好不要提供一个空的数组,比如新的IClasspathEntry [0]。 我认为最好是给一个正确的长度的数组(否则一个新的将由List#toArray创build,这是一个浪费性能)。

由于types擦除,解决方法是给出数组的组件types。

例:

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

此实现中的typesC允许创build具有列表元素types的超types的组件types的数组。

用法:

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

等待泛化的generics

正如前面指出的那样,

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

这也将起作用:

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

但是,在第一种情况下,将会生成一个新的数组。 你可以看到这是如何在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; } 

请参阅番石榴的Iterables.toArray(list, class)

工作的解决scheme!

只需复制你的项目中的界面和类。 这个 :

 public interface LayerDataTransformer<F, T> { T transform(F from); Collection<T> transform(Collection<F> from); T[] toArray(Collection<F> from); } 

和这个 :

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

用法。

声明BaseDataLayerTransformer的子类

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

并使用:

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