一. ArrayList
//属性
transient Object[] elementData;
ArrayList底层是用一个名为“elementData”的Object数组实现的。
- grow
//方法
private void grow(int minCapacity) {
//minCapacity 数组想装下新元素所需的最小容量
// overflow-conscious code
int oldCapacity = elementData.length;
//新容量是原容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity >> 1);
//还不够就以所需最小容量为新长度
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
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);
}
ArrayList实现数组不定长的主要方法,当add()新元素导致数组长度不够时调用grow()函数扩容。具体扩容方法是新建一个数组,将原数组的内容复制到新数组里。然后旧的数组所占内存因为没有被引用自动回收。然后add方法加入新元素。
- remove
public E remove(int index) {
rangeCheck(index);
modCount++;
E oldValue = elementData(index);
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,numMoved);
elementData[--size] = null; // clear to let GC do its work
return oldValue;
}
remove方法的底层实现是先将原数组要删除元素的后面的部分覆盖到要删除元素的位置,再删掉数组最后的多余元素。删除的实质是数组复制,这也是ArrayList增删效率低的原因。
二、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;
}
}
LinkedList底层实现是一个 双向链表,每一个结点是泛型类Node的一个实例,item是节点的内容,这里next和prev相当于一个指向结点的指针。这种数据结构让LinkedList具有增删效率高、查找效率低的特点。
LinkedList中包含的方法都是双向链表的相关的算法,头插法、尾插法等,没看到什么特别的。自己写对链表进行操作的函数时时尤其要注意三种情况:
- 数组是空的
- 在头尾节点时进行的操作
- 对值为null的对象的属性进行操作会报空指针异常