JDK源码解析之Stack

前言:

    Stack一般来说用的比较少点,因为其数据结构特殊性,所以在一些特殊的场景,还是能发挥出巨大作用的。

    Stack(栈):参照java.util.Stack的注释来看,它具有后进先出的特性(LIFO)。

    从网络上截一个图(如有侵权,请联系作者),简单表示下链表结构

JDK源码解析之Stack_第1张图片

    可以看到,其主要操作就是入栈和出栈操作,a0元素是最早入栈的,现在在栈底,an是最后一个入栈的,在栈顶,执行出栈操作时an先出来,最后才是a0

 

1.Stack结构分析

/**
 * The Stack class represents a last-in-first-out
 * (LIFO) stack of objects. 
 */
public
class Stack extends Vector {
    

    可以看到,其继承了Vector,而Vector又是线程安全版的ArrayList,所以,其底层存储仍然是数组

 

2.构造方法

public Stack() {
}

    构造比较简单,只有一个空参构造方法

 

3.基本操作

    1)入栈操作

// Stack.push()
public E push(E item) {
    // 直接调用了Vector.addElement()方法
    addElement(item);
    return item;
}

// Vector.addElement()
public synchronized void addElement(E obj) {
    modCount++;
    // 扩容,存放值到数组最后一位
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = obj;
}

    入栈操作就是将数据添加到数组最后一位

 

    2)查看栈顶元素操作

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

    if (len == 0)
        throw new EmptyStackException();
    // 获取数组最后一位的数据
    return elementAt(len - 1);
}

    3)出栈操作

public synchronized E pop() {
    E       obj;
    int     len = size();

    // 1.获取站顶元素
    obj = peek();
    // 2.调用Vector.removeElementAt()
    removeElementAt(len - 1);

    return obj;
}

// Vector.removeElementAt()
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--;
    // 将最后一位置为null
    elementData[elementCount] = null; /* to let gc do its work */
}

    可以看出,入栈出栈操作都是线程安全操作,基本操作都是交由Vector来处理的。

 

    4)查询元素操作

public synchronized int search(Object o) {
    // 交由Vector.lastIndexOf()处理
    int i = lastIndexOf(o);

    // 这一步比较有意思,如果获取到元素的索引位置
    // 用size()减去其值,为什么要这样做呢?
    if (i >= 0) {
        return size() - i;
    }
    return -1;
}

// Vector.lastIndexOf()
// 遍历数组查询对象
public synchronized int lastIndexOf(Object o, int index) {
    if (index >= elementCount)
        throw new IndexOutOfBoundsException(index + " >= "+ elementCount);

    if (o == null) {
        for (int i = index; i >= 0; i--)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = index; i >= 0; i--)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

    注意:栈的查询返回的索引与数组查询返回的索引不同,为什么会有这么大的差距呢?

    主要是因为它们的结构不同,对于数组的最后一个元素而言,相对栈而言是栈顶元素,index也就是1,所以获取元素在数组后的index后,还需要使用size()-index

 

 

你可能感兴趣的:(CoreJava,JDK源码解析,Stack)