List代表一种线性表的数据结构,ArrayList则是一种顺序存储的线性表。ArrayList底层采用数组来保存每个集合元素,LinkedList则是一种链式存储的线性表。其本质上就是一个双向链表,但它不仅实现了List接口,还实现了Deque接口。也就是说LinkedList既可以当成双向链表使用,也可以当成队列使用,还可以当成栈来使用(Deque代表双端队列,即具有队列的特征,也具有栈的特征)。
ArrayList底层采用一个elementData数组来保存所有的集合元素,因此ArrayList在插入元素时需要完成下面两件事情。
- 保证ArrayList底层封装的数组长度大于集合元素的个数;
- 将插入位置之后的所有数组元素“整体搬家”,向后移动一“格”。
反过来,当删除ArrayList集合中指定位置的元素时,程序也要进行”整体搬家”,而且还需将被删索引处的数组元素赋为null。下面是ArrayList集合的remove(int index)方法的源代码。
public E remove(int index) {
//如果index是大于或等于size,抛出异常
RangeCheck(index);
modCount++;
//index索引处的元素
E oldValue = (E) elementData[index];
//计算需要"整体搬家"的元素个数
int numMoved = size - index - 1;
//当numMoved大于0时,开始搬家
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
//释放被删除的元素
elementData[--size] = null; // Let gc do its work
return oldValue;
}
对于ArrayList集合而言,当程序向ArrayList中添加、删除集合元素时,ArrayList底层都需要对数组进行”整体搬家” 因此性能非常差。
但如果程序调用get(int index)方法来取出ArrayList集合中的元素时,性能和数组几乎相同–非常快。下面是ArrayList集合get(int index)方法的源代码。