栈的实现其实有两种, 一种是使用Vector实现的, 一种是使用队列行数据结构实现的具体参考一下两种方式

实现方式1 线程安全的

写在前面, 在讲栈之前, 先要讲一下Vector, Vector其实是类似于ArrayList的, 其内部本身实现的方式也是使用数组存放元素,其与ArrayList不同之处在于, Vector对数组的操作是同步的, 其是一个线程安全的集合类.(方法是synchronized)

整体的代码非常简单, 注意这个栈的操作也是线程安全的

public
class Stack<E> extends Vector<E> &#123;
    /**
     * Creates an empty Stack.
     */
    public Stack() &#123;
    &#125;

    /**
     * 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) &#123;
        addElement(item);

        return item;
    &#125;

    /**
     * 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() &#123;
        E       obj;
        int     len = size();

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

        return obj;
    &#125;

    /**
     * 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() &#123;
        int     len = size();

        if (len == 0)
            throw new EmptyStackException();
        return elementAt(len - 1);
    &#125;

    /**
     * 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() &#123;
        return size() == 0;
    &#125;

    /**
     * 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) &#123;
        int i = lastIndexOf(o);

        if (i >= 0) &#123;
            return size() - i;
        &#125;
        return -1;
    &#125;

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

实现方式2 非线程安全

我们在上一个文章中详细说明了LinkedList, 其实LinkedList也是可以做为栈使用的.参考一片文章Java 集合源码剖析, ArrayDequeLinkedListDeque的两个通用实现,由于官方更推荐使用AarryDeque用作栈和队列.

从名字可以看出ArrayDeque底层通过数组实现,为了满足可以同时在数组两端插入或删除元素的需求,该数组还必须是循环的,即循环数组(circular array),也就是说数组的任何一点都可能被看作起点或者终点。ArrayDeque是非线程安全的(not thread-safe),当多个线程同时使用的时候,需要程序员手动同步;另外,该容器不允许放入null元素。

public class ArrayDeque<E> extends AbstractCollection<E> implements Deque<E>, Cloneable, Serializable&#123;&#125;

可以直接参考一下Java 集合源码剖析无非就是对数组两端的增删改查, 特殊的在于ArrayDeque实现的是循环数组.

非常经典的一个方法

public void addFirst(E e) &#123;
        if (e == null)
            throw new NullPointerException();
        elements[head = (head - 1) & (elements.length - 1)] = e; 
        if (head == tail)
            doubleCapacity();
    &#125;

head = (head - 1) & (elements.length - 1), 这一句由于elements.length 始终是2的整数倍, 且是int类型因此

elements.length -1 的二进制应该是
0 xxxxxxxx 1111(初始化是16 0-15)
因此首次head -1 = -1 (1的反码+1 就是-1)
因该是(补码)
111111111111111 
与上面的按位与被置为整数15 (保留低位4)
下一次
    public void addLast(E e) &#123;
        if (e == null)
            throw new NullPointerException();
        elements[tail] = e;
        if ( (tail = (tail + 1) & (elements.length - 1)) == head)
            doubleCapacity();
    &#125;

Comments

⬆︎TOP