算法 第四版 內置庫java.util.Stack 理解

前言:

記錄在閱讀算法 第四版 謝路雲譯時的疑惑和解惑思路

在1.3揹包、隊列、和棧 的答疑部分時的問答

文章主體:

問 Java標準庫中有棧和隊列嗎?

答 有,也沒有。Java中有一個內置的庫,叫做java.util.Stack ,但你需要棧的時候請不要使用它。它新增了幾個一般不屬於棧的方法,例如獲取第一個i元素。它還允許從棧底添加元素(而非棧頂),所以他可以當作隊列來使用! 儘管擁有這些額外的操作看起來很有用,但它們其實是累贅。我們使用某種數據結構類型不僅僅是爲了獲得我們能夠想象的各種操作,也是爲了準確地指定我們所需要的操作。這麼做的主要好處在於系統能夠防止我們執行一些意外的操作。java.util.Stack API 是寬接口的一個典型例子,我們通常會極力避免出現這種情況。

疑惑

看到書中推薦說不要使用它,作爲Java自身的內置庫我還是十分的信任,所以帶着疑惑去查看了源碼。

/*
 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.util;

/**
 * The <code>Stack</code> class represents a last-in-first-out
 * (LIFO) stack of objects. It extends class <tt>Vector</tt> with five
 * operations that allow a vector to be treated as a stack. The usual
 * <tt>push</tt> and <tt>pop</tt> operations are provided, as well as a
 * method to <tt>peek</tt> at the top item on the stack, a method to test
 * for whether the stack is <tt>empty</tt>, and a method to <tt>search</tt>
 * the stack for an item and discover how far it is from the top.
 * <p>
 * When a stack is first created, it contains no items.
 *
 * <p>A more complete and consistent set of LIFO stack operations is
 * provided by the {@link Deque} interface and its implementations, which
 * should be used in preference to this class.  For example:
 * <pre>   {@code
 *   Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>
 *
 * @author  Jonathan Payne
 * @since   JDK1.0
 */
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;
}


可以看到,源碼之中只有6個方法

public Stack()

public E push(E item) 

public synchronized E pop()

public synchronized E peek() 

public boolean empty() 

public synchronized int search(Object o) 

並沒有暴露其他操作方法。


於是我使用直接寫代碼測試,一敲代碼就發現,之前走入了誤區,並且明白了它指的寬接口含義。


關鍵句在:public class Stack<E> extends Vector<E>

它繼承的是Vector 一個自動增長的對象數組 。

所以也就繼承了它的操作,同時它的方法也是基於vector實現的。


然後也就越發覺得書中這句話的精妙了


儘管擁有這些額外的操作看起來很有用,但它們其實是累贅。我們使用某種數據結構類型不僅僅是爲了獲得我們能夠想象的各種操作,也是爲了準確地指定我們所需要的操作。這麼做的主要好處在於系統能夠防止我們執行一些意外的操作。



如有不正確之處,還望指出 0 0 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章