Stack
version:1.8
Stack为JDK对于栈(先进后出)这一数据结构的实现,其继承Vector类,其操作主要是对Vector类的一些封装。
public class Stack<E> extends Vector<E>
栈主要有三个操作:
push:入栈
pop:出栈
peek:查看栈顶元素
push
源码如下:
public E push(E item) {
addElement(item);
return item;
}
addElement(E obj)为继承自Vector类的方法,其源码如下:
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
Vector内部维持Object数组elementData以存储元素,通过elementCount记录元素个数,ensureCapacityHelper(elementCount + 1)判断是否需要进行扩容。
protected Object[] elementData;
protected int elementCount;
注意到变量modCount,其来自于Vector的父类AbstractList, transient 关键字意味着该变量不参与序列化过程。
protected transient int modCount = 0;
由Vector类中sort()方法中该变量的使用,可推测该变量用于多线程的同步问题。
@SuppressWarnings("unchecked")
@Override
public synchronized void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, elementCount, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
peek
源码如下:
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
其核心操作为Vector类的elementAt() 方法:
public synchronized E elementAt(int index) {
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
}
return elementData(index);
}
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
pop
源码如下:
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
pop通过peek获得栈顶元素返回,通过Vector类的removeElementAt(len - 1)方法移除栈顶元素:
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--;
elementData[elementCount] = null; /* to let gc do its work */
}
易知,该方法将数组后半部分元素整体向前移动一位,将最后一位引用指向null,从而移除对该元素的引用,由于栈每次仅移除栈顶元素,故移动该步骤实际未生效。
综上,JDK对栈的实现本质是对数组的封装。