JDK 1.8 Vector与Stack源码分析

Vector类从JDk 1.0开始就存在了,其类的继承关系如下:
Vector继承关系图
从上图可以发现Vector的继承关系与ArrayList的继承关系相同,功能上Vector与ArrayList也是一样的,都是一个扩展的列表。区别在于Vector是线程安全的,而ArrayList不是线程安全的。
Stack类代表的是一个LIFO的栈,该类的继承关系如下:
Stack继承关系图
可以看到Stack继承自Vector类,在Vector的基础上提供了5个操作使Vector具备Stack的性质。五个方法分别是push、pop、peek、检测栈是否为空基于一个搜索方法。
下面先介绍Vector的源码,最后介绍一下Stack。

Vector源码介绍

构造器

Vector有四个构造方法,其内部有两个重要的参数,一个是elementCount代表当前元素个数,一个是capacityIncrement,代表当列表元素满了之后增加的容量。如果不设置capacityIncrement,那么Vector容量扩展时默认将扩展两倍,在ArrayList源码分析中,我们知道ArrayList在扩容时默认将扩展1.5倍,所以这又是ArrayList与Vector的一个区别。

public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }


public Vector(int initialCapacity) {
        this(initialCapacity, 0);
    }


 public Vector() {
        this(10);
    }  


 public Vector(Collection<? extends E> c) {
        elementData = c.toArray();
        elementCount = elementData.length;
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
    }   

从上面代码还可以看到,Vector初始时容量为10,而ArrayList初始容量为0。

添加操作

下面就以add(E e)方法为例介绍一个,其余方法与ArrayList中的流程类似。add()方法的实现如下:

public synchronized boolean add(E e) {
        modCount++;
        //确保容量足够
        ensureCapacityHelper(elementCount + 1);
        //添加元素
        elementData[elementCount++] = e;
        return true;
    }

从上面代码可以看到,add()方法用synchronized关键字修饰,所以是线程安全的,ensureCapacityHelper()方法用于确保容量足够,不够时扩展容量,其实现如下:

private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

可以看到,当需要扩容时,将调用grow()方法。

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

可以看到,如果capacityIncrement为0时,那么newCapacity将会是两倍的oldCapacity,后面的操作与ArrayList中的相同。下面看一下ArrayList的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);
    }

从上面就可以看出两个类在得到newCapacity变量时的区别。
其他add方法与ArrayList相同,只不过每个方法多了synchronized关键字修饰。

其余操作

其余操作与ArrayList类似,只不过每个方法都多了synchronized关键字,从而保证了Vector类的线程安全。

Stack源码分析

Stack类的实现比较简单,只是在Vector的基础上添加了一个方法,下面是Stack类的实现:

public
class Stack<E> extends Vector<E> {
    /**
     * Creates an empty Stack.
     */
    public Stack() {
    }

    /**
     * Pushes an item onto the top of this stack. This has exactly
     * the same effect as:
     * <blockquote><pre>
     * addElement(item)</pre></blockquote>
     *
     * @param   item   the item to be pushed onto this stack.
     * @return  the <code>item</code> argument.
     * @see     java.util.Vector#addElement
     */
    public E push(E item) {
        addElement(item);

        return item;
    }

    /**
     * Removes the object at the top of this stack and returns that
     * object as the value of this function.
     *
     * @return  The object at the top of this stack (the last item
     *          of the <tt>Vector</tt> object).
     * @throws  EmptyStackException  if this stack is empty.
     */
    public synchronized E pop() {
        E       obj;
        int     len = size();

        obj = peek();
        removeElementAt(len - 1);

        return obj;
    }

    /**
     * Looks at the object at the top of this stack without removing it
     * from the stack.
     *
     * @return  the object at the top of this stack (the last item
     *          of the <tt>Vector</tt> object).
     * @throws  EmptyStackException  if this stack is empty.
     */
    public synchronized E peek() {
        int     len = size();

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

    /**
     * Tests if this stack is empty.
     *
     * @return  <code>true</code> if and only if this stack contains
     *          no items; <code>false</code> otherwise.
     */
    public boolean empty() {
        return size() == 0;
    }

    /**
     * Returns the 1-based position where an object is on this stack.
     * If the object <tt>o</tt> occurs as an item in this stack, this
     * method returns the distance from the top of the stack of the
     * occurrence nearest the top of the stack; the topmost item on the
     * stack is considered to be at distance <tt>1</tt>. The <tt>equals</tt>
     * method is used to compare <tt>o</tt> to the
     * items in this stack.
     *
     * @param   o   the desired object.
     * @return  the 1-based position from the top of the stack where
     *          the object is located; the return value <code>-1</code>
     *          indicates that the object is not on the stack.
     */
    public synchronized int search(Object o) {
        int i = lastIndexOf(o);

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

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = 1224463164541339165L;
}

从上面的代码可以看到,Stack内部一共五个方法,其中三个方法都加了synchronized关键字,是线程安全的,而push和empty方法调用了Vector的方法,由于Vector中的addElement()和size()方法都是线程安全的,所以Stack的每个方法也都是线程安全的,所以它和Vector一样,都是线程安全的。

总结

Vector与ArrayList的最大区别就是Vector是线程安全的,而ArrayList不是线程安全的。另外区别还有:
- ArrayList不可以设置扩展的容量,默认1.5倍;Vector可以设置扩展的容量,如果没有设置,默认2倍
- ArrayList的无参构造方法中初始容量为0,而Vector的无参构造方法中初始容量为10。
- Vector线程安全,ArrayList线程不安全。

Vector和它的子类Stack都是线程安全的集合。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值