前言
前言点击此处查看:
http://blog.csdn.net/wang7807564/article/details/79113195
Collection
List
List是一种有序的Collection,使用此接口能够精确地控制每个元素插入的位置。用户能够使用索引来访问List中的元素,每个元素的索引是固定的,我们可以认为List是一种动态的数组。
实现List接口的常用类有LinkedList,ArrayList,Vector和Stack.
ArrayList
ArrayList的底层实现原理是开辟出一块数组区域,能够加入任何类型的元素,包括null.ArrayList的size(),isEmpty(),get(),set()方法运行时间为常数。但是使用add()方法添加n个元素需要O(n)的时间,其他的方法运行时间为线性。
也就是说,使用ArrayList是要求随机读取的场景,因为Array在随机读取的时候效率很高,但是在频繁插入和删除的场景中,效率就会相对差一些。
ArrayList的部分核心JDK源码是这样的:
//增加
public void add(int index, E element) {
rangeCheckForAdd(index);
ensureCapacityInternal(size + 1); // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,size - index);
elementData[index] = element;
size++;
}
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
int numNew = a.length;
ensureCapacityInternal(size + numNew); // Increments modCount
System.arraycopy(a, 0, elementData, size, numNew);
size += numNew;
return numNew != 0;
}
//删除
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;
}
//查询
public E get(int index) {
rangeCheck(index);
return elementData(index);
}
//修改
public E set(int index, E element) {
rangeCheck(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
其中,elementData是一个Object类型的数组,用于存储元素。当添加元素的时候,需要先判断elementData数组的长度,然后为其扩容,扩容的核心函数是grow(),其源代码是:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
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);
}
LinkedList
LinkedList与ArrayList类似,都类似于动态数组。与ArrayList的区别在于,LinkedList的底层数据结构是链表,这使得其在增加和删除某个元素的时候速度很快,是一个常数的复杂度,但是,在随机读取某个元素的时候,效率就会比较差,因为游标需要移动。所以,在大量增加和删除元素的时候,我们可以使用LinkedList,需要随机读取元素的时候,选用ArrayList.
此外LinkedList提供额外的get(),remove(),insert()方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。
它的JDK实现源代码是:
transient int size = 0;
/**
* Pointer to first node.
* Invariant: (first == null && last == null) ||
* (first.prev == null && first.item != null)
*/
transient Node<E> first;
/**
* Pointer to last node.
* Invariant: (first == null && last == null) ||
* (last.next == null && last.item != null)
*/
transient Node<E> last;
//链表的数据结构
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;
}
}
//添加元素
public void add(int index, E element) {
checkPositionIndex(index);
if (index == size)
linkLast(element);
else
linkBefore(element, node(index));
}
/**
* Links e as first element.
*/
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++;
}
/**
* Links e as last element.
*/
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++;
}
//删除
public void remove() {
checkForComodification();
if (lastReturned == null)
throw new IllegalStateException();
Node<E> lastNext = lastReturned.next;
unlink(lastReturned);
if (next == lastReturned)
next = lastNext;
else
nextIndex--;
lastReturned = null;
expectedModCount++;
}
//查询
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
//修改
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
Vector & Stack
Vector与ArrayList很类似,区别是Vector的方法是同步的,这些方法被加上synchronized关键字修饰,这将在后面的高并发中具体阐述。
由Vector创建的Iterator,虽然和ArrayList创建的Iterator实现的同一接口,但是,由于Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(如添加或删除了一些元素),这时调用Iterator的方法时将抛出 ConcurrentModificationException异常,需要手动去捕获该异常。
Stack类继承自Vector,实现的是一个堆栈的数据结构。Stack提供5个额外的方法使得Vector可以被当作堆栈使用。这五个额外的方法分别是:push()和pop()方法入栈和出栈,peek()方法用于得到栈顶的元素,empty()方法测试堆栈是否为空,search()方法检测某元素在堆栈中的位置。Stack刚创建后是元素是空的。
Stack继承自Vector,自然也是由synchronized修饰过的同步容器。而除了这两个类,其他实现List接口的容器类并没有实现同步,在多线程场景下需要注意线程安全问题。有关同步容器,将在后面的高并发中具体涉及到。