List 是重要的数据结构之一。最常用的的便是: ArrayList、Vector 和 LinkedList 三种了,他们类图如下图所示:
由上图可知,这三种 List 都实现了 Collection 和 List 接口。
这三种不同的实现中,ArrayList 和 Vector 使用了数组实现,封装了对内部数组的操作。它们俩唯一的区别是 ArrayList 没有任何一个方法是同步的,而 Vector 则是做了线程同步。我们之后均以 ArrayList 为例进行讲解。
LinkList 使用了双向链表数据结构,并且维护了 first 和 last 两个成员变量来指示链表的头和尾。这和 ArrayList 是截然不同的实现技术,也决定了它们适用于不同的场景中。
LinkedList 是由一系列表项连接而成的。一个表项总是分为三个部分,分别是:元素内容,前驱表项 和 后驱表项,如下图所示:
在 JDK 的视线中,不管 LinkedList 是否为空,链表中总是有一个 header 表项,它即表示链表的开始,也表示链表的结尾。
下面以增加和删除为例,比较 ArrayList 和 LinkList 的不同之处。
1、增加元素到列表尾端
在 ArrayList 中增加元素到队列端尾的代码如下:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // 确保内部数组有足够的空间
elementData[size++] = e;
return true;
}
/**
* 分配的最大内存。
* 有些虚拟机会为数组保留了一些头部内容,试图分配更多的空间会引起内存溢出
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void ensureCapacityInternal(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1); //计划扩容到现在容量的1.5倍
if (newCapacity - minCapacity < 0) //如果新容量小于最小需要的