将通用列表转换为数组
我已经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);