list转数组可以通过调用toarray的两种重载完成,这里主要讨论一下第二种有参的方法,具体的使用仅大概介绍一下
使用形式:
ArrayList<Integer> list=new ArrayList<>();
Integer[] a;
//1.存在问题:“将 'arr.toArray()' 转换为 'Integer[]' 会为任意非 null 值生成 'ClassCastException'”
//也就是将返回的obj【】强转为integer【】,要求list里面没有null值才能这样
a= (Integer[]) list.toArray();
//2.使用含参的,参数是一个空的T[]数组,这种是最好使的
a=list.toArray(new Integer[0]);
//3.含参,但参数是一个已有的数组——这就容易出问题了,也就是这篇要讨论的地方
a=list.toArray(b);
推荐是使用第二种,但是第三中种问题在哪呢——看源码
作为对比,先看无参方法:
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
//ctrl+b
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
//ctrl+b
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
可以看到这里的newlength参数,? (T[]) new Object[newLength]
说明返回的obj数组,长度就是list内元素的长度(elementdata是list内存储数据的数组,size是存储数据的个数,即list.size()就是直接返回size),然后将list元素都copy过去返回。
而含参方法:
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
可以看到,如果参数数组T[]的长度小于list内元素的个数,那么就和无参的差不多,只不过是额外指定了返回值的类型;这也就是上面说的第二种推荐的方法。
但如果a.length > size,就有问题了——arraycopy仍然,但是a[size] = null;
什么意思呢——这并不是像c里的数组,说把它截断成size那么长,而就是仅仅给size位置赋一个null值,这就很坑了。
尤其是参数a就是接收结果的数组,或者其他有用的数组的情况:如果是其他有用的数组,里面的数据会被直接覆盖成list的内容,而且长度超过size的话并不会被截短;如果是a=list.toArray(a);
,当a长度小于size还好,如果超过,那么返回的数组里面可能仍然有原先不需要的数据,而且仅靠一个null值分割(有个null本身就很不好了),这对于后面遍历数组操作的时候是很要命了。
测试结果:
(原数据被覆盖了,而且length也没有变短)
结论:千万不要图省事,写个a=list.toArray(a);
,那个参数一定多打几个字写成new Integer[0]
另:有时候需要的是int数组,而list只能得到integer数组——强制转换是不行的,这里给一种办法(试了下,性能并不是很快,大佬有其他办法的话教教):
arr = Arrays.stream(integerArr).mapToInt(Integer::intValue).toArray();
//上面那个不能处理null值,如果可能有null的话下面这个将null变为0
arr = Arrays.stream(integerArr).mapToInt(i -> i != null ? i : 0).toArray();