我已经搜索过这个,但不幸的是,我没有得到正确答案。
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;
}
}
测试它:
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)
如何解决这个问题?
更新
我想要这种方法,因为有时我的代码中的类型太长了:
newEntries.toArray(new IClasspathEntry[0])
我希望打电话:
toArray(newEntries)
最后
创建这样的方法似乎是不可能的,非常感谢你们!
答案 0 :(得分:43)
这是由于类型擦除。在编译中删除了泛型,因此Helper.toArray
将被编译为返回Object[]
。
对于这种特殊情况,我建议您使用List.toArray(T[])
。
String[] array = list.toArray(new String[list.size()]);
答案 1 :(得分:35)
您可以调用list.toArray(T[] array)
而不必担心自己实现它,但正如aioobe所说,由于类型擦除,您无法创建泛型类型的数组。如果您需要返回该类型,则需要自己创建一个类型化实例并将其传入。
答案 2 :(得分:18)
如果你想通过蛮力制作你的方法,并且你可以保证你只会在某些限制下调用该方法,你可以使用反射:
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的子类型,因此如果第一个元素是子类型,则将列表的第一个元素视为代表类型将产生一个转换异常。这意味着T不能是一个接口。此外,如果您的列表为空,您将获得索引超出范围的异常。
仅当您计划调用列表的第一个元素与列表的通用类型匹配的方法时,才应使用此选项。使用提供的toArray方法更加健壮,因为提供的参数告诉您要返回的数组类型。
答案 3 :(得分:9)
您无法像在此处一样实例化Generic类型:
T[] array = (T[]) new Object[list.size()];
因为,如果T
与某个类型绑定,则会将新的Object
数组类型转换为有界类型T
。我建议改用List.toArray(T[])
方法。
答案 4 :(得分:8)
请参阅Guava的Iterables.toArray(list, class)
。
示例:
@Test
public void arrayTest() {
List<String> source = Arrays.asList("foo", "bar");
String[] target = Iterables.toArray(source, String.class);
}
答案 5 :(得分: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());
}
答案 6 :(得分:4)
String[] array = list.toArray(new String[0]);
答案 7 :(得分:4)
如前所述,这将起作用:
String[] array = list.toArray(new String[0]);
这也有效:
String[] array = list.toArray(new String[list.size()]);
但是,在第一种情况下,将生成一个新数组。你可以看到这是implemented in 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;
}
答案 8 :(得分:3)
问题是不是String的数组的组件类型。
此外,最好不提供空数组,例如新的IClasspathEntry [0]。 我认为最好给出一个具有正确长度的数组(否则将使用List#toArray创建一个新的,这会浪费性能)。
由于类型擦除,解决方案是给出数组的组件类型。
示例:
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);
}
此实现中的类型C允许创建一个组件类型为列表元素类型的超类型的数组。
用法:
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 !
}
等待具体化的仿制品..
答案 9 :(得分:1)
只需复制项目中的界面和类。 这个:
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);
答案 10 :(得分:1)
我使用这个简单的功能。 IntelliJ只是讨厌类型强制转换T [] ,但它的工作正常。
public static <T> T[] fromCollection(Class<T> c, Collection<T> collection) {
return collection.toArray((T[])java.lang.reflect.Array.newInstance(c, collection.size()));
}
并且通话看起来像这样:
Collection<Integer> col = new ArrayList(Arrays.asList(1,2,3,4));
fromCollection(Integer.class, col);
答案 11 :(得分:0)
拥有通用enter code here
时,您将能够在运行时知道对象的类。因此,实现它的最佳方法是这样的:
List<T>
为什么需要public static <T> T[] list2Array(Class<T[]> clazz, List<T> elements)
{
T[] array = clazz.cast(Array.newInstance(clazz.getComponentType(), elements.size()));
return elements.toArray(array);
}
参数?
因为,我们有一个通用的列表,它不会提供必要的信息,以在保持类型安全的同时,获取我们正在寻找的精确类型的数组。与其他答案相反,这将使您返回一个Object数组或在编译时导致警告。这种方法将为您提供一个干净的解决方案。这里的“ hack”是Class<T[]>
调用,对于您声明clazz.cast()
实例的任何类型,该调用都不会发出警告。
现在,如何使用它?
简单,只需这样命名:
list2Array()
这是此的编译示例:https://ideone.com/wcEPNI
为什么起作用?
之所以起作用,是因为编译器将类文字视为List<String> list = Stream.of("one", "two", "three").collect(Collectors.toList());
String[] numbers = list2Array(String[].class, list);
System.out.println(Arrays.toString(numbers));
的实例。这也适用于接口,枚举,任意维数组(例如java.lang.Class
),基元和关键字void。
String[].class
本身是通用的(声明为Class
,其中Class<T[]>
代表T[]
对象表示的类型),这意味着{{1的类型}}是Class
。
注意:由于基本体不能用于类型变量,因此您将无法获得基本体数组。