本文转载自微信公众号“Java中文社区”,作者雷哥。转载本文请联系Java中文社区公众号。在这正式开始之前,先给大家解释一下“栈”这个词的含义,因为之前有读者对这个词有些疑惑。Stack翻译成中文就是栈的意思,但是为了和Heap(堆)区别,我们一般把Stack简称为栈。因此,当“stack”连在一起时,可能表示Stack,而当“heap,stack”中间有分号时,则表示Heap(堆)和Stack(栈),如下图所示:JDK栈的实现下面说说正题。接下来我们看看栈在JDK中是如何实现的。在JDK中,stack的实现类是Stack,它的继承关系如下图所示:Stack中包含的方法如下图所示:其中最重要的是方法有:push:stack方法(添加数据);pop:弹出栈并返回当前元素(移除数据);peek:查询栈顶元素。Stack的实现源码如下:publicclassStackextendsVector{/***创建一个空栈*/publicStack(){}/***Push方法,调用Vector的add方法#addElement*/publicEpush(Eitem){addElement(item);returnitem;}/***出栈并返回当前元素,调用Vector移除元素的方法#removeElementAt*/publicsynchronizedEpop(){Eobj;//return当前待移除栈顶元素信息intlen=size();obj=peek();//查询当前栈顶元素removeElementAt(len-1);//移除栈顶元素returnobj;}/***查询栈顶元素,调用Vector#elementAt查询方法*/publicsynchronizedEpeek(){intlen=size();//查询当前栈的长度if(len==0)//如果栈为空,抛出一个异常直接thrownewEmptyStackException();returnelementAt(len-1);//查询栈顶元素信息}/***判断栈是否为空*/publicbooleanempty(){returnsize()==0;}//忽略其他方法。..}从上面的源码可以看出,Stack中的核心方法调用了父Vector类中的方法,Vector类的核心源码:publicclassVectorextendsAbstractListimplementsList,RandomAccess,Cloneable,java.io.Serializable{protectedObject[]elementData;//存储数据的容器protectedintelementCount;//存储数据的容量值/***添加数据*/publicsynchronizedvoidaddElement(Eobj){modCount++;//的参数统计容器改变ensureCapacityHelper(elementCount+1);//确认容器大小,如果容量超过然后扩容elementData[elementCount++]=obj;//将数据存入数组}/***移除元素(根据下标移除)*/publicsynchronizedvoidremoveElementAt(intindex){modCount++;//统计的参数containerarechanged//数据正确性检查if(index>=elementCount){thrownewArrayIndexOutOfBoundsException(index+">="+elementCount);}elseif(index<0){thrownewArrayIndexOutOfBoundsException(index);}intj=elementCount-index-1;if(j>0){//删除不是最后一个元素//将删除元素之后的所有元素向前移动System.arraycopy(elementData,index+1,elementData,index,j);}elementCount--;//数组容量-1elementData[elementCount]=null;//将最后一个元素赋为null(删除tail元素)}/***查询元素(根据下标)*/publicsynchronizedEelementAt(intindex){//安全验证if(index>=elementCount){thrownewArrayIndexOutOfBoundsException(index+">="+elementCount);}//根据subsc返回数组中的元素riptreturnelementData(index);}//忽略其他方法...}对于上面的源码,可以说是最难理解的了最重要的是System#arraycopy这个方法,它的作用其实就是移动后面的元素将被删除的元素(不是末尾元素)一个一个往前,比如下面的代码:Object[]elementData={"Java","Hello","world","JDK","JRE"};intindex=3;intj=elementData.l长度索引-1;System.arraycopy(elementData,index+1,elementData,index,j);//System.arraycopy(elementData,4,elementData,3,1);System.out.println(Arrays.toString(elementData));其运行结果为:[Java,Hello,world,JRE,JRE]也就是说,当我们要删除下标为3的元素时,需要将3之后的元素向前移动,所以数组的值From{"Java","Hello","world","JDK","JRE"}到[Java,Hello,world,JRE,JRE],最后我们只需要删除尾元素就可以实现删除的功能数组中的非末尾元素总结从上面的源码我们可以知道JDK中的栈(Stack)也是通过物理结构数组来实现的,我们通过操作物理数组来实现逻辑结构栈的功能。栈的应用经过前面的学习,我们已经对栈有了一定的了解,那么栈在我们日常工作中有哪些应用呢?接下来,我们一起来看看吧。浏览器回滚栈的特性是后进先出(LastInFirstOut,后进先出),所以利用这个特性就可以实现浏览器的回滚功能,如下图:函数调用栈是程序中最经典的一个application是一个函数调用栈(或方法调用栈)。例如,操作系统为每个线程分配独立的内存空间。该内存被组织成一个“堆栈”结构,用于存储函数调用。临时变量。每进入一个函数,临时变量就会作为栈帧被压入栈中。当被调用的函数执行并返回时,该函数对应的栈帧就会被弹出栈。为了让大家更好的理解,我们来看一下这段代码的执行过程。intmain(){inta=1;intret=0;intres=0;ret=add(3,5);res=a+ret;System.out.println(res);reuturn0;}intadd(intx,inty){intsum=0;sum=x+y;returnsum;}从代码中可以看出,main()函数调用add()函数获取计算结果,添加到临时变量a中,最后打印资源价值为了让大家清楚的看到这个过程对应的函数栈中的出栈和入栈操作,我画了一张图。该图显示了执行add()函数时的函数调用堆栈。栈的复杂度分为两个维度:时间维度:指执行当前算法所消耗的时间,我们通常用“时间复杂度”来描述;空间维度:指执行当前算法需要多少内存空间,我们通常用“空间复杂度”来描述。这两个复杂度用大O表示法来表示,比如下面的代码:int[]arr={1,2,3,4};for(inti=0;i