一、概述
Vector 是JDK1.0提供的集合类,Stack是Vector的子类,LinkedList是JKD1.2提供的,是双向链表。
二、源码分析
Vector的实现基本跟ArrayList一样,所以就不重复分析了,简单挑出几个方法进行分析
扩容方法:
private void ensureCapacityHelper(int minCapacity) {
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object[] oldData = elementData;
int newCapacity = (capacityIncrement > 0) ?
(oldCapacity + capacityIncrement) : (oldCapacity * 2);
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
从该方法就能分析出来,Vector扩容的特点,Vector扩容取决于capacityIncrement变量的值,个人理解相当于步进长度,默认是0,Vector会进行两倍扩容,或者采取原容量+步进长度来扩容,ArrayList会增大0.5倍在加1(HashMap跟负载因子相关默认是0.75),其他方法基本跟ArrayList相同,不再赘述,但是需要注意的是Vector是线程安全的集合,内部方法基本都有同步锁。
下面再来看一下Stack“栈”,Stack是Vector的子类,通过一定的封装来达到LIFO后入先出来模拟栈的特性。常用的方法有如下三个:
public E push(E item) {
addElement(item);
return item;
}
压栈,添加数据到栈里。
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
弹栈,弹出最后插入的数据,其中的peek方法直接弹出最后数据,如果没有会抛出异常,所以遍历的时候要加上判断
empty()。另外Stack也是个线程安全类。
再来看一下LinkedList ,它也是List接口的一个实现类,支持clone,序列化,还是实现了Deque接口——双端接口,
所以LinkedList可以实现FIFO,或者实现栈的功能,它提供了丰富的方法让我们可以灵活使用来达到自己想要的效果。
先来看一下它的实现基础——属性
private transient Entry<E> header = new Entry<E>(null, null, null);//标示头元素
private transient int size = 0;//存储队列大小
其中Entry是一个静态类,内部属性有E element 存储当前节点的value,Entry<E> next 存储当前节点的下一个Entry的引用,Entry<E> previous 存储当前节点的前一个Entry的引用。所以整个LinkedList的内部数据结构我们就明白了,其实就是一个链表,我们可以通过header来从前向后,或者从后向前进行操作,从而实现双端操作。
默认生成的linkedList不会额外创建空间,header.next = header.previous = header;另外header是不存储数值的,只是作为一个标记节点,真正存储元素开始的位置是是header.next。整个LinkedList可以看做一个“环”。通过数据结构我们就能知道,LinkedList查找效率比较低——从头或者尾一步步找,但是删除效率很高——找到之后直接修改引用即可,不用像ArrayList还要复制数组,另外LinkedList也允许存入null
常用的方法有:
public E getFirst()//得到第一个的元素
public E getLast()//得到最后的元素
实现了List接口所以很多方法跟ArrayList一样,内部实现稍有不同
主要看一下删除方法
public E remove(int index) {
return remove(entry(index));
}
/**
* Returns the indexed entry.
*/
private Entry<E> entry(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+size);
Entry<E> e = header;
if (index < (size >> 1)) {//判断index离头还是尾近
for (int i = 0; i <= index; i++)
e = e.next;
} else {
for (int i = size; i > index; i--)
e = e.previous;
}
return e;
}
private E remove(Entry<E> e) {
if (e == header)
throw new NoSuchElementException();
E result = e.element;
e.previous.next = e.next;
e.next.previous = e.previous;
e.next = e.previous = null;
e.element = null;
size--;
modCount++;
return result;
}
通过index查找速度比通过对象找快,内部有判断选择合适的方向开始查找,通过分析可以看出LinkedList的删除操作时间复杂度是o(n)(要先遍历查找)。
三、总结
Vector与Stack都是JDK1.0提供的线程安全类,由于同步效率比较低,没有同步需求的情况下不建议使用该集合。
LinkedList是非线程安全类,是双向链表,删除速度快,查找慢。