ArrayList 和 LinkedList
一、ArrayList
1.ArrayList的默认初始化容量
private static final int DEFAULT_CAPACITY = 10;
这个也可以在创建一个对象时自己指定:
ArrayList<Object> list=new ArrayList<>(12);
2.ArrayList底层使用数组维护
transient Object[] elementData;
3.扩容机制
private void grow(int minCapacity) { //minCapacity:扩容后最小需要容量
// overflow-conscious code
int oldCapacity = elementData.length; //旧容量
int newCapacity = oldCapacity + (oldCapacity >> 1); //新容量为1.5倍旧容量
if (newCapacity - minCapacity < 0) //新容量 小于 最小需要容量
newCapacity = minCapacity; //就把新容量提到minCapacity(最小需要容量)
// 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) `hugeCapacity()` 方法来比较 minCapacity和MAX_ARRAY_SIZE
//如果minCapacity大于最大容量,则新容量则为`Integer.MAX_VALUE`,
//否则,新容量大小则为 MAX_ARRAY_SIZE 即为 `Integer.MAX_VALUE - 8`。
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
//定义了 MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
//对minCapacity和MAX_ARRAY_SIZE进行比较
//若minCapacity大,将Integer.MAX_VALUE作为新数组的大小
//若MAX_ARRAY_SIZE大,将MAX_ARRAY_SIZE作为新数组的大小
//MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
4.重写了sort()方法
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);//底层调用的还是Arrays.sort()
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
二、LinkedList
1.LinkedList底层由 双向链表 维护
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
transient int size = 0; //记录数组长度
transient Node<E> first; //头指针
transient Node<E> last; //尾指针
2.头插法与尾插法
//头插法
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
//尾插法
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
3. LinkedList的add()方法默认采用尾插法
public boolean add(E e) {
linkLast(e);
return true;
}
三、两者的比较
1.ArrayList 是基于数组的,所以它使用索引在数组中搜索和读取数据是很快的O(1);但是要插入、删除数据却是开销很大的,因为这需要移动数组中插入位置之后的的所有元素O(n)。
2.LinkedList是基于双向链表的,它的随机访问集合元素时性能较差,因为需要在双向列表中找到要index的位置O(n);但在插入,删除操作是更快的O(1)。
3.LinkedList需要更多的内存,因为ArrayList的每个索引的位置是实际的数据,而LinkedList中的每个节点中还需要存储前后节点的索引。