Android开发Android技术知识Android开发

聊一聊Vector与Stack

2018-03-27  本文已影响250人  姜康

Java Collection系列下面有List,Set,Queue等,而Vector属于List下面的一个实现。

特点

简要分析

先看一下有哪些重要的属性:

protected Object[] elementData;
protected int elementCount;
protected int capacityIncrement;

这其中elementData是一个数组,用来实际存储数据;
容量方面有两个概念,一个是elementCount,一个是capacityIncrement;
其中elementCount代表的是中有效元素的个数,也就是说从elementData[0]到elementData[elementCount - 1]中的是实际的数据项。
而capacityIncrement代表的是,当你需要扩容的时候,一次性增加的容量大小。比如,在你向Vector中插入大量数据之前,可以增加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);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

实际扩容的时候,调用的是grow方法。
如果 capacityIncrement > 0 ,则容量新增capacityIncrement大小;
如果 capacityIncrement <=0 , 则容量新增一倍;
然后再对最小应该满足的容量,和最大的容量配置进行判断,保证稳定性。

其中还有一个方法,可以直接设置容量:

 public synchronized void setSize(int newSize) {
        modCount++;
        if (newSize > elementCount) {
            ensureCapacityHelper(newSize);
        } else {
            for (int i = newSize ; i < elementCount ; i++) {
                elementData[i] = null;
            }
        }
        elementCount = newSize;
    }

如果新容量 > 当前的容量,则进行扩容,然后将null元素添加到Vector后面;
如果新容量 <= 当前的容量,则从索引值为newSize的开始,后面的元素全部设置为null;

说完了Vector,就顺便说一下Stack吧。

Stack

Stack继承自Vector,在其基础之上添加了一些入栈,出栈的操作,如push()/pop()/peek()等。

其也是线程安全的;

public
class Stack<E> extends Vector<E> {

    public Stack() {
    }

   
    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;
    }

    public synchronized E peek() {
        int     len = size();

        if (len == 0)
            throw new EmptyStackException();
        return elementAt(len - 1);
    }

    public boolean empty() {
        return size() == 0;
    }

    public synchronized int search(Object o) {
        int i = lastIndexOf(o);

        if (i >= 0) {
            return size() - i;
        }
        return -1;
    }

    private static final long serialVersionUID = 1224463164541339165L;
}


从Stack的源码中可以看到,它的入栈,出栈,查询操作均是利用Vector中的实现方法,并且都是同步的,因此是线程安全,但是性能是有所损耗。

通常可以利用Deque或者Deque的实现类来替换Stack,比如:

Deque<Integer> stack = new ArrayDeque<Integer>();

其中ArrayDeque并非线程安全的,这一点在使用的时候得注意,而且它不支持null元素。

ArrayDeque可以用来作为栈或者队列:

用作Stack的时候,它比Stack快;
用作Queue的时候,它比LinkedList(LinkedList本身实现了Deque接口,因为可以作为Queue来使用)快;

公众号
上一篇下一篇

猜你喜欢

热点阅读