在学习ArrayList过程中,看到了源码出现这样的一段话:
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity) {
if (initialCapacity > 0) {
this.elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
this.elementData = EMPTY_ELEMENTDATA;
} else {
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
}
}
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
这是它的三个构造函数,核心在这个:
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c) {
elementData = c.toArray();
if ((size = elementData.length) != 0) {
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
} else {
// replace with empty array.
this.elementData = EMPTY_ELEMENTDATA;
}
}
这里大概就是说传入参数为集合类,elementData 为一个Object数组,这里有几个问题:
首先是这里面的一句注释: c.toArray might (incorrectly) not return Object[] (see 6260652) 这里的意思是toArray可能会不正确地返回数组对象Object[];举个例子
@Test
public void toArrayTest(){
List<String> StringList = new LinkedList<String>();
StringList.add("123");
Object[] objs = StringList.toArray();
System.out.println(objs.getClass());
objs[0] = new Object();
objs= Arrays.asList("zhen", "xiang").toArray();
System.out.println(objs.getClass());
objs[0] = new Object();
System.out.println(Arrays.asList("zhen", "xiang").toArray().getClass());
}
输出:
class [Ljava.lang.Object;
class [Ljava.lang.String;
java.lang.ArrayStoreException: java.lang.Object
at com.example.demo.test1.toArrayTest(test1.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
可以看到,执行完ArrayList构造函数的elementData = c.toArray()之后,这个时候正如注释所说的,toArray可能会不正确地返回数组对象Object[],这里就返回了String[];这个其实是个官方bug,可以去到官方bug库(链接:https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652 )找得到相关的解释,并且这个是jdk1.5的bug;不过在jdk10已经修复了。我这个是jdk8,从这里可以知道的是,调用toArray() 时,实际上调用的是其具体实现类中的 toArray() 方法。如果这个时候你进行了向下转型(上面例子里的objs[0] = new Object(),这里objs是String数组,但是却进行了向下转型)是不安全的,会抛出ArrayStoreException异常。
这个有什么关系呢?有的,现在先不说,现在只要记得存在这样一个bug就行,接下来继续看构造函数,可以看到在进行完toArray操作之后,他会对elementData长度进行判断,如果不是0,那么会进行这样的判断:
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, size, Object[].class);
重点来看一下这里,上面知道,elementData.getClass() != Object[].class是存在的,而elementData本身就是一个Object[],看起来似乎elementData = Arrays.copyOf(elementData, size, Object[].class);这个操作有点多余,因为就算不进行这样的操作,那么这里也不会出问题。实际上,会出问题的,这里不出问题,别的地方出问题而已,答案其实已经在上面的例子里面了:如果不进行调用Arrays.copyOf()方法,那么可能会出现抛出ArrayStoreException异常的情况。比如:
ArrayList<Object> objectList = new ArrayList<Object>(Arrays.asList("zhen", "xiang"));
System.out.println(Arrays.asList("zhen", "xiang").toArray().getClass());
objectList.set(1,new Object());
如果这里不进行Arrays.copyOf操作,上面这个例子就会抛出ArrayStoreException异常
那么,这里Arrays.copyOf干嘛用的应该就清楚了:就是把数组强行转换成Object[]