目录
Stack
栈(Stack)是动态集合,在删除操作上它所移除的元素是预先设定的。在栈(Stack)中,被删除的元素是最近插入的,因此栈(Stack)实现的是一种后进先出(last-in,first-out,LIFO)策略。在Java中,使用简单的数组来实现其结构,栈(Stack)上的INSERT操作称为压入(PUSH),无元素参数的DELETE操作称为弹出(POP)。----摘自《算法导论 第三版》
Stack继承关系
java.lang.Object
↳ java.util.AbstractCollection<E>
↳ java.util.AbstractList<E>
↳ java.util.Vector<E>
↳ java.util.Stack<E>
Stack继承及依赖图
构造函数
public Stack()
API
public synchronized E peek()
public E push(E item)
public synchronized E pop()
public synchronized int search(Object o)
public boolean empty()
注1:Stack是线程安全的,在push操作中虽然未加锁,但内部操作中调用父类Vector的addElement 操作是加锁的,Vector的addElement 操作声明如下。
public synchronized void addElement(E obj)
注2:当调用push操作时,已加载的父类Vector已初始化底层数组,并默认数组长度为10(关于ClassLoader,可查看JVM相关类初始化问题),因此当进行了10次push操作,会触发父类Vector的grow函数进行动态数组增长。 源码如下
/**
* This implements the unsynchronized semantics of ensureCapacity.
* Synchronized methods in this class can internally call this
* method for ensuring capacity without incurring the cost of an
* extra synchronization.
*
* @see #ensureCapacity(int)
*/
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
注3:数组Capacity MAX_ARRAY_SIZE=Integer.MAX_ARRAY_SIZE(2^31 - 1) - 8,当栈增长>Integer.MAX_ARRAY_SIZE - 8,则MAX_ARRAY_SIZE就会更替,这是与之前超过默认长度的操作稍有不同。
注4:Stack Search(重要),此操作为线程安全的,这边使用的是父类Vector中lastIndexOf操作,其具体使用for倒序循环来查找出具体位置,时间复杂度为O(n),为此对其三种循环进行测试。
注4---源码如下:
import java.util.Iterator;
import java.util.Stack;
/**
* @Author: zhangzhirong
* @Description:
* @Date:Created in 10:49 2018/11/27/027
* @Modify By:
**/
public class StackForForEachIteratorTime {
private static final int COUNT = 1000000;
private static Stack stack = new Stack();
public static void init(){
//初始化,生成对象个数
for(int i=0;i<COUNT;i++){
stack.push(i);
}
}
//Iterator遍历
public static long testIterator(){
//开始编译执行时间
long start =System.nanoTime();
int i;
Iterator iterator = stack.iterator();
while ( iterator.hasNext()) {
i = (int) iterator.next();
}
//执行完后的时间
long end =System.nanoTime();
return (end- start) / 1000;
}
//foEach循环遍历
public static long testForEach(){
//开始编译执行时间
long start =System.nanoTime();
int i;
for(Object p:stack){
i = (int)p;
}
//执行完后的时间
long end =System.nanoTime();
return (end- start) / 1000;
}
//for循环遍历
public static long testFor(){
//开始编译执行时间
long start =System.nanoTime();
int j;
for(int i=0;i<stack.size();i++){
j=(int)stack.pop();
}
//执行完后的时间
long end =System.nanoTime();
return (end- start) / 1000;
}
public static void main(String[] args) {
init();
System.out.println("Stack---Iterator迭代遍历的消耗时间为:"+testIterator());
System.out.println("Stack---ForEach遍历的消耗时间为:"+testForEach());
System.out.println("Stack---For循环遍历的消耗时间为:"+testFor());
}
}
注4---测试结果如下:
Iterator迭代遍历的消耗时间为:43877
ForEach遍历的消耗时间为:39972
For循环遍历的消耗时间为:40207
Process finished with exit code 0
注4---个人结论:在栈(Stack)内部,for循环遍历在各方面统计消耗更小,因此此源码开发者选取for循环进行查找操作。