Java集合系列05之Vector&Stack源码分析及List总结

系列文章

前言

Vector是矢量队列,JDK1.0版本添加的类,是一个动态数组,与ArrayList不同的是Vector支持多线程访问,是线程安全的,因为内部很多方法都被synchronized关键字修饰了,有同步锁,而且其内部有很多不属于集合框架的方法。其定义如下:

public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

Vector继承了AbstractList,实现了List,RandomAccess, Cloneable, java.io.Serializable四个接口,支持随机访问。

Stack表示先进后出(FILO)的堆栈,是一种常见的数据结构,Stack继承了Vector,由于Vector是通过数组实现的,因此Stack也是通过数组实现的,而非链表。前面介绍LinkedList时,我们也说过可以把LinkedList当作Stack使用。

本文源码分析基于jdk 1.8.0_121

继承关系

Vector&Stack继承关系

java.lang.Object
  |___ java.util.AbstractCollection<E>
      |___ java.util.AbstractList<E>
          |___ java.util.Vector<E>
              |___ java.util.Stack<E>
所有已实现的接口:
Serializable, Cloneable, Iterable<E>, Collection<E>, List<E>, RandomAccess

关系图

Vector&Stack关系图

Vector的数据结构和ArrayList类似,包含了elementData,elementCount,capacityIncrement三个成员变量:

  • elementDataObject[]类型的数组,保存了Vector的数据,是Vector的底层实现,它是个动态数组,在添加数据过程中不断扩展容量,初始化时若没有指定数组大小,则默认的数组大小是10;
  • elementCount是动态数组的实际大小;
  • capacityIncrement是数组容量增长的相关参数,创建Vector时如果指定了capacityIncrement,则Vector每次容量增加时,数组容量增加的大小就是capacityIncrement;创建Vector时没有指定capacityIncrement,则Vector每次容量增加一倍。

Stack中只定义了一些关于堆栈的操作方法,具体见下文。

构造函数

Vector一共有四个构造函数

// initialCapacity是Vector的默认容量大小
// capacityIncrement是每次数组容量增长的大小
public Vector(int initialCapacity, int capacityIncrement) {
    super();
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
    this.elementData = new Object[initialCapacity];
    this.capacityIncrement = capacityIncrement;
}

// initialCapacity是Vector的默认容量大小
// 数组容量增加时,每次容量会增加一倍。
public Vector(int initialCapacity) {
    this(initialCapacity, 0);
}

// 默认构造函数,默认容量为10
public Vector() {
    this(10);
}

// 创建包含集合c的数组
public Vector(Collection<? extends E> c) {
    elementData = c.toArray();
    elementCount = elementData.length;
    if (elementData.getClass() != Object[].class)
        elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}

Stack只有一个默认构造函数:

public Stack() {
}

API

Vector API

synchronized boolean        add(E e)
             void           add(int index, E element)
synchronized boolean        addAll(Collection<? extends E> c)
synchronized boolean        addAll(int index, Collection<? extends E> c)
synchronized void           addElement(E obj)
synchronized int            capacity()
             void           clear()
synchronized Object         clone()
             boolean        contains(Object o)
synchronized boolean        containsAll(Collection<?> c)
synchronized void           copyInto(Object[] anArray)
synchronized E              elementAt(int index)
Enumeration<E>              elements()
synchronized void           ensureCapacity(int minimumCapacity)
synchronized boolean        equals(Object o)
synchronized E              firstElement()
             E              get(int index)
synchronized int            hashCode()
synchronized int            indexOf(Object o, int index)
             int            indexOf(Object o)
synchronized void           insertElementAt(E obj, int index)
synchronized boolean        isEmpty()
synchronized E              lastElement()
synchronized int            lastIndexOf(Object o, int index)
synchronized int            lastIndexOf(Object o)
synchronized E              remove(int index)
             boolean        remove(Object o)
synchronized boolean        removeAll(Collection<?> c)
synchronized void           removeAllElements()
synchronized boolean        removeElement(Object obj)
synchronized void           removeElementAt(int index)
synchronized boolean        retainAll(Collection<?> c)
synchronized E              set(int index, E element)
synchronized void           setElementAt(E obj, int index)
synchronized void           setSize(int newSize)
synchronized int            size()
synchronized List<E>        subList(int fromIndex, int toIndex)
synchronized <T> T[]        toArray(T[] a)
synchronized Object[]       toArray()
synchronized String         toString()
synchronized void           trimToSize()

Stack API

       boolean     empty()
synchronized E     peek()
synchronized E     pop()
             E     push(E item)
synchronized int   search(Object o)

源码分析

Vector源码分析

成员变量

// 保存Vector数据
protected Object[] elementData;

// 实际数量
protected int elementCount;

// 容量增长数量
protected int capacityIncrement;

// 最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

改变容量值

// 将当前容量值设置为实际元素个数
public synchronized void trimToSize() {
    modCount++;
    int oldCapacity = elementData.length;
    if (elementCount < oldCapacity) {
        elementData = Arrays.copyOf(elementData, elementCount);
    }
}

确定容量

// 确认Vector容量,修改次数+1
public synchronized void ensureCapacity(int minCapacity) {
    if (minCapacity > 0) {
        modCount++;
        ensureCapacityHelper(minCapacity);
    }
}

// 帮助函数,minCapacity大于现在数组实际长度时扩容
private void ensureCapacityHelper(int minCapacity) {
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

// 扩容,capacityIncrement>0 则将容量增大capacityIncrement
// 否则直接将容量扩大一倍
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                     capacityIncrement : oldCapacity);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}

// 当minCapacity超出Integer.MAX_VALUE时,minCapacity变为负数,抛出异常
private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

// 设置容量值为 newSize
public synchronized void setSize(int newSize) {
    modCount++;
    // 如果newSize大于elementCount,则调整容量
    if (newSize > elementCount) {
        ensureCapacityHelper(newSize);
    } else { 
        // 如果newSize小于或等于elementCount,则将newSize位置开始的元素都设置为null
        for (int i = newSize ; i < elementCount ; i++) {
            elementData[i] = null;
        }
    }
    elementCount = newSize;
}

返回Enumeration

// 返回Vector中所有元素对应的Enumeration
public Enumeration<E> elements() {
    return new Enumeration<E>() {
        int count = 0;
        
        // 是否有下一个元素 类似Iterator的hasNext()
        public boolean hasMoreElements() {
            return count < elementCount;
        }
        
        // 获取下一个元素
        public E nextElement() {
            synchronized (Vector.this) {
                if (count < elementCount) {
                    return elementData(count++);
                }
            }
            throw new NoSuchElementException("Vector Enumeration");
        }
    };
}

增加元素

// 增加元素
public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}

// index处添加元素
public void add(int index, E element) {
    insertElementAt(element, index);
}

// 在index处插入元素
public synchronized void insertElementAt(E obj, int index) {
    modCount++;
    if (index > elementCount) {
        throw new ArrayIndexOutOfBoundsException(index
                                                 + " > " + elementCount);
    }
    ensureCapacityHelper(elementCount + 1);
    System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
    elementData[index] = obj;
    elementCount++;
}

// 添加集合c
public synchronized boolean addAll(Collection<? extends E> c) {
    modCount++;
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityHelper(elementCount + numNew);
    System.arraycopy(a, 0, elementData, elementCount, numNew);
    elementCount += numNew;
    return numNew != 0;
}

// index处开始,将集合c添加到Vector中
public synchronized boolean addAll(int index, Collection<? extends E> c){
    modCount++;
    if (index < 0 || index > elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityHelper(elementCount + numNew);

    int numMoved = elementCount - index;
    if (numMoved > 0)
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);

    System.arraycopy(a, 0, elementData, index, numNew);
    elementCount += numNew;
    return numNew != 0;
}

// 将给定元素添加到Vector中
public synchronized void addElement(E obj) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = obj;
}

删除元素

// 查找并删除元素obj
// 查找到则删除,返回true
// 查找不到则返回false
public synchronized boolean removeElement(Object obj) {
    modCount++;
    int i = indexOf(obj);
    if (i >= 0) {
        removeElementAt(i);
        return true;
    }
    return false;
}

// 删除index处元素
public synchronized void removeElementAt(int index) {
    modCount++;
    if (index >= elementCount) {
        throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                 elementCount);
    }
    else if (index < 0) {
        throw new ArrayIndexOutOfBoundsException(index);
    }
    int j = elementCount - index - 1;
    if (j > 0) {
        System.arraycopy(elementData, index + 1, elementData, index, j);
    }
    elementCount--;
    elementData[elementCount] = null; /* to let gc do its work */
}

// 删除所有元素
public synchronized void removeAllElements() {
    modCount++;
    // Let gc do its work
    for (int i = 0; i < elementCount; i++)
        elementData[i] = null;

    elementCount = 0;
}

// 删除元素o
public boolean remove(Object o) {
    return removeElement(o);
}

// 删除index位置处元素,并返回该元素
public synchronized E remove(int index) {
    modCount++;
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);
    E oldValue = elementData(index);

    int numMoved = elementCount - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--elementCount] = null; // Let gc do its work

    return oldValue;
}

设置元素

// 设置index处元素为element,并返回index处原来的值
public synchronized E set(int index, E element) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

// 设置index处元素为obj
public synchronized void setElementAt(E obj, int index) {
    if (index >= elementCount) {
        throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                 elementCount);
    }
    elementData[index] = obj;
}

获取元素

// 获取index处元素
public synchronized E get(int index) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    return elementData(index);
}

Stack源码分析

package java.util;

public class Stack<E> extends Vector<E> {
   
    // 构造函数
    public Stack() {
    }

    // 栈顶元素入顶
    public E push(E item) {
        // addElement的实现在Vector.java中
        addElement(item);
        return item;
    }

    // 删除栈顶元素
    public synchronized E pop() {
        E obj;
        int len = size();
        obj = peek();
        // removeElementAt的实现在Vector.java中
        removeElementAt(len - 1);
        return obj;
    }

    // 返回栈顶元素,不执行删除操作
    public synchronized E peek() {
        int len = size();
        if (len == 0)
            throw new EmptyStackException();
        return elementAt(len - 1);
    }

    // 是否为空
    public boolean empty() {
        return size() == 0;
    }

    // 查找元素o在栈中位置,由栈底向栈顶方向
    public synchronized int search(Object o) {
        int i = lastIndexOf(o);
        if (i >= 0) {
            return size() - i;
        }
        return -1;
    }

    // 版本ID
    private static final long serialVersionUID = 1224463164541339165L;
}

Stack的源码比较简单,内部也是通过数组实现的,执行push时将元素追加到数组末尾,执行peek时返回数组末尾元素(不删除该元素),执行pop时取出数组末尾元素,并将该元素从数组中删除。

Vector遍历方式

  • 迭代器遍历
Iterator iter = vector.iterator();
while(iter.hasNext()) {
    iter.next();
}
  • 随机访问
for (int i=0; i<vector.size(); i++) {
    vector.get(i);        
}
  • foreach循环
for (Integer integ:vector) {
    ;
}
  • Enumeration遍历
Enumeration enu = vector.elements();
while(enu.hasMoreElements()) {
    enu.nextElement();
}

以上各种方式中,随机访问效率最高。

List总结

概述

下面是List的关系图:

List

上图总结如下:

  • List是接口,继承Collection,是一个有序队列
  • AbstractList是抽象类,继承了AbstractCollection类,并实现了List接口,提供了 List 接口的大部分实现
  • AbstractSequentialList 继承自 AbstractList,是 LinkedList 的父类,提供了List接口大部分实现。 AbstractSequentialList 实现了链表中的“随机访问”方法
  • ArrayList,LinkedList,Vector,Stack是四个队列集合,List的四个实现类

比较

队列集合 特点 使用场景 访问效率
ArrayList 数组队列,动态增长,非线程安全 快速随机访问场景下,单线程 随机访问效率高,随机插入、随机删除效率低
LinkedList 双向链表,可当做队列,堆栈,双端队列 快速插入,删除场景下,单线程 随机访问效率低,随机插入、随机删除效率低
Vector 向量队列,动态增长,线程安全 多线程场景下
Stack 栈,先进后出

参考内容

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,332评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,930评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,204评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,348评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,356评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,447评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,862评论 3 394
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,516评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,710评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,518评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,582评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,295评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,848评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,881评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,121评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,737评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,280评论 2 341

推荐阅读更多精彩内容