相同处 a. 都直接或者间接继承了AbstractList,都支持以索引的方式操作元素。 b. 都不必担心容量问题,ArrayList通过动态数组来保存数据,当容量不足时,自动扩容,LinkedList是以双链表的形式来实现的,不存在容量问题。 c. 都时线程不安全的,一般用于单线程环境下,在多线程环境下使用Collections.synchronized()来保证数据的一致性。
不同处 a. LinkedList是由链表实现的,ArrayList是由数组实现的。 b. 相对于ArrayList而言,LinkedList实现Deque接口,在保留了索引操作元素的同时,也实现了双链表所具有的功能,这也决定了LinkedList的特性。 c. 多集合元素的操作效率不同,LinkedList善于增删,ArrayList善于查询和修改,这个本质就是数组和链表的区别。
效率分析 a. ArrayList的随机访问效率高于LinkedList的源码分析:
随机访问指的是通过索引去查找元素
LinkedList获取指定索引处值的源码:
// Positional Access Operations/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/public E get(int index) {
//检查值是否越界
checkElementIndex(index);
//返回节点的值return node(index).item;
}
/**
* Returns the (non-null) Node at the specified element index.
*///通过二分法来寻找节点的值
Node<E> node(int index) {
// assert isElementIndex(index);if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
ArrayList得到数组值的源码分析
/**
* Returns the element at the specified position in this list.
*
* @param index index of the element to return
* @return the element at the specified position in this list
* @throws IndexOutOfBoundsException {@inheritDoc}
*/public E get(int index) {
//检查数组是否越界
rangeCheck(index);
//调用elementData(int index)方法return elementData(index);
}
// Positional Access Operations//返回index处的值@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
LinkedList的增删效率高于ArrayList的源码分析
LinkedList删除源码
/**
* Removes the element at the specified position in this list. Shifts any
* subsequent elements to the left (subtracts one from their indices).
* Returns the element that was removed from the list.
*
* @param index the index of the element to be removed
* @return the element previously at the specified position
* @throws IndexOutOfBoundsException {@inheritDoc}
*/public E remove(int index) {
//检查是否越界
checkElementIndex(index);
//调用unlink(Node<E> x)return unlink(node(index));
}
/**
* Unlinks non-null node x.
*///不再链接当前节点
E unlink(Node<E> x) {
// assert x != null;//得到节点的值final E element = x.item;
//得到后节点final Node<E> next = x.next;
//得到前节点final Node<E> prev = x.prev;
//如果前节点为空,意味这不再链接的节点就是头节点if (prev == null) {
//后节点变为头节点
first = next;
} else {
//否则,前节点的下一个节点不再指向当前节点,指向后节点
prev.next = next;
//当前节点的前节点变为空,也就是断掉当前节点的前引用
x.prev = null;
}
//如果后节点为空,也就是当前节点是尾节点if (next == null) {
//前节点变为尾节点
last = prev;
} else {
//否则,后节点的前节点是前节点
next.prev = prev;
//当前节点的前节点引用设空
x.next = null;
}
//值变为空
x.item = null;
//大小减一
size--;
//修改次数增加
modCount++;
//返回被修改的节点return element;
}
LinkedList增加的源码原理和删除节点的原理相反,但都是对节点的修改,不再贴出源码
ArrayList增加的源码分析
publicvoidadd(int index, E element) {
//检查数组越界
rangeCheckForAdd(index);
//自动扩容
ensureCapacityInternal(size + 1); // Increments modCount!!//copy旧数组,形成新数组,这个地方是最耗费时间的,也是ArrayList增加元素效率低的关键
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
privatevoidensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
privatevoidensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious codeif (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* The maximum size of array to allocate.
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/privatestaticfinalint MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*///着重分析这里的源码privatevoidgrow(int minCapacity) {
// overflow-conscious code//得到旧容量的大小int oldCapacity = elementData.length;
//欲扩容的容量是旧容量的1.5倍int newCapacity = oldCapacity + (oldCapacity >> 1);
//欲扩容的容量和需要的实际容量的比较if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 欲扩容的容量和max容量比较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);
}
privatestaticinthugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflowthrownew OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}