c.toArray might (incorrectly) no
在ArrayList的ArrayList(Collection<? extends E> c)
构造器中看到了这句注释:c.toArray might (incorrectly) not return Object[] (see 6260652)。翻了下文档,这是一个官方bug。
A DESCRIPTION OF THE PROBLEM :
The Collection documentation claims that
collection.toArray()
is "identical in function" to
collection.toArray(new Object[0]);
However, the implementation of Arrays.asList does not follow this: If created with an array of a subtype (e.g. String[]), its toArray() will return an array of the same type (because it use clone()) instead of an Object[].
If one later tries to store non-Strings (or whatever) in that array, an ArrayStoreException is thrown.
Either the Arrays.asList() implementation (which may return an array of component type not Object) or the Collection toArray documentation (which does not allow argumentless toArray() to return arrays of subtypes of Object) is wrong.
大概意思就是说,collection.toArray()理论上应该返回Object[]。然而使用Arrays.asList得到的list,其toArray方法返回的数组却不一定是Object[]类型的,而是返回它本来的类型。例如Arrays.asList(String)得到的list,使用toArray会得到String数组。如果向这个数组中存储非String类型的元素,就会抛出ArrayStoreException
异常。
List<String> str1 = new ArrayList<String>();
str1.add("ab");
str1.add("bc");
Object[] strs1 = str1.toArray();
System.out.println("strs1:");
System.out.println(str1.toString());
// class [Ljava.lang.Object;
System.out.println(strs1.getClass());
// class java.util.ArrayList
System.out.println(str1.getClass());
List<String> str2 = Arrays.asList(new String[]{"ab", "bc"});
Object[] strs2 = str2.toArray();
System.out.println("strs2:");
System.out.println(str2.toString());
// class [Ljava.lang.String;
System.out.println(strs2.getClass());
// class java.util.Arrays$ArrayList
System.out.println(str2.getClass());
// java.lang.ArrayStoreException
strs2[0] = new Object();
可以看到,使用Arrays.asList()得到的str,它其实是java.util.Arrays$ArrayList,是Arrays的静态内部类ArrayList,它的toArray方法与java.util.ArrayList是不一样的。
执行结果
// Arrays类
@SafeVarargs
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
/**
* @serial include
*/
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
...
// 返回参数本来的类型
public <T> T[] toArray(T[] a) {
int size = size();
if (a.length < size)
return Arrays.copyOf(this.a, size,
(Class<? extends T[]>) a.getClass());
System.arraycopy(this.a, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
}
// ArrayList类
// 返回Object[]类型
public Object[] toArray() {
return Arrays.copyOf(elementData, size);
}
扩展
- 相同类型的变量(str1、str2),调用相同的方法(toArray),得到的返回结果却不一样——多态。
- Object[]类型的数组strs2,存放一个Object类型的实例报错——向上转型与向下转型。