Java集合之Stack 源码分析
1.简介
栈是数据结构中一种很重要的数据结构类型,因为栈的后进先出功能是实际的开发中有很多的应用场景。Java API中提供了栈(Stacck)的实现,简单使用如下所示
package com.test.collections;
import java.util.Stack;
public class StackTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Stack<String> stack = new Stack<String>();
stack.add("China");
stack.add("Japan");
stack.add("Russia");
stack.add("England");
System.out.println(stack.size()+"<="+stack.capacity());
System.out.println(stack.elementAt(0));
System.out.println(stack.get(0));
System.out.println(stack.peek());
System.out.println(stack.push("France"));
System.out.println(stack.pop());
System.out.println(stack.iterator());
System.out.println(stack.empty());
System.out.println(stack.isEmpty());
System.out.println(stack.search("Russia"));
}
}
2.继承结构
Stack类继承了Vector类,而Vector类继承了AbstractList抽象类,实现了List接口,Cloneable接口,RandomAcces接口以及Serializable接口,需要指出的Vector内部还有两个内部类ListItr和Itr,Itr在继承Vector的同时实现了Iterator接口,而ListItr在继承了Itr类的同时实现了ListIterator接口。
3.源码解读
通过Stack类发现含有的方法有pop(),peek(),push(Object),search(Object),empty()方法,其他值的方法是从Vector类继承而来,通过源码可以发现Vector有几个属性值:protected Object[] elementData,protected int elementCount;protected int capacityIncrement;private static final int MAX_ARRAY_SIZE = 2147483639;通过这几属性我们可以发现,Stack底层是采用数组来实现的,elementData用于保存Stack中的每个元素;elementCount用于动态的保存元素的个数,capacityIncrement用来保存Stack的容量(一般情况下应该是大于elementCount);MAX_ARRAY_SIZE 用于限制Stack能够保存的最大值数量。
a.removeElementAt()
public synchronized void removeElementAt(int paramInt) {
this.modCount += 1;
if (paramInt >= this.elementCount)
throw new ArrayIndexOutOfBoundsException(paramInt + " >= "
+ this.elementCount);
if (paramInt < 0)
throw new ArrayIndexOutOfBoundsException(paramInt);
int i = this.elementCount - paramInt - 1;
if (i > 0)
System.arraycopy(this.elementData, paramInt + 1, this.elementData,
paramInt, i);
this.elementCount -= 1;
this.elementData[this.elementCount] = null;
}
removeElementAt()方法用于移除某个位置的元素,需要指出元素的位置,这个方法来之与Stack的父类Vector;通过代码我们可以发现它的实现是首先判断参数是否合法然后将这个位置前的所有元素都向后移动了一位,而且把元素的个数-1,最后把原来位置最上面的那个元素置为空,从而实现了删除某个元素的操作。
b:elementData(int)
E elementData(int paramInt) {
return this.elementData[paramInt];
}
elementData(int)返回某一位置的元素的具体值,通过这个方面也可以看出Stack底层是有一个数组来实现的 。
c:elementAt(int)
public synchronized E elementAt(int paramInt) {
if (paramInt >= this.elementCount)
throw new ArrayIndexOutOfBoundsException(paramInt + " >= "
+ this.elementCount);
return elementData(paramInt);
}
elementAt(int paramInt)首先判断参数是否合法,然后就直接调用elementData(paramInt)返回具体的对象值。
d:peek()
public synchronized E peek() {
int i = size();
if (i == 0)
throw new EmptyStackException();
return elementAt(i - 1);
}
通过源码就可以发现peek()只是获取了第一个位置的元素的值(Stack的下标和数组保持一致都是从0开始,最大到元素总数-1)
e:pop()
public synchronized E pop() {
int i = size();
Object localObject = peek();
removeElementAt(i - 1);
return localObject;
}
pop()方法的实现是首先获取Stack的元素数量,然后调用peek()方法获取栈顶的第一个元素,然后调用removeElementAt(int)删除栈顶元素,最后将元素的值返回。
f:addElement(E paramE)
public synchronized void addElement(E paramE) {
this.modCount += 1;
ensureCapacityHelper(this.elementCount + 1);
this.elementData[(this.elementCount++)] = paramE;
}
addElement(E)方法是个很重要的方法,因为它实现了元素的添加。它在添加元素的时候首先将modCount加1,ensureCapacityHelper()主要用于保障Stack的容量,如果超过当前容量则调用grow()方法进行容量增加,如果操作最大的容量MAX_ARRAY_SIZE就会抛出异常。第三步才会实现元素的添加,就是i将该元素添加到栈顶,并且将元素的数目加1;
g:search(Object)
public synchronized int search(Object paramObject) {
int i = lastIndexOf(paramObject);
if (i >= 0)
return (size() - i);
return -1;
}
该方法返回所查找对象所处的位置,如果不存在在返回-1;通过代码可以发现它的实现过程是这样的,首先通过lastLindexOf(Object)方法返回从栈底到栈顶最下面的的那个元素的下标,然后利用元素的总数目减去所处的下标就得到了元素的位置(),并且返回否则返回-1;(需要注意的改位置返回的是从栈顶到栈底开始所处的位置,栈顶元素的位置为1)
h:empty()
public boolean empty() {
return (size() == 0);
}
直接返回元素的数目与0比较的关系,size()方法是通过this.elementCount返回了栈元素的数目。
4.其他(小结)
通过源码我们可以看到Vector底层是一个数组,说明Stack的实现是通过数组来实现的,然后通过对数组的操作来模仿栈的各种功能。而且在源码中Vector的很多方法都是synchronized 的,也就是说是线程安全,所以说在多线程中是可以安全使用的,不过这样效率上肯定是会降低的。
Java集合之Stack 源码分析的更多相关文章
- 死磕 java集合之DelayQueue源码分析
问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...
- 死磕 java集合之PriorityBlockingQueue源码分析
问题 (1)PriorityBlockingQueue的实现方式? (2)PriorityBlockingQueue是否需要扩容? (3)PriorityBlockingQueue是怎么控制并发安全的 ...
- 死磕 java集合之PriorityQueue源码分析
问题 (1)什么是优先级队列? (2)怎么实现一个优先级队列? (3)PriorityQueue是线程安全的吗? (4)PriorityQueue就有序的吗? 简介 优先级队列,是0个或多个元素的集合 ...
- 死磕 java集合之CopyOnWriteArraySet源码分析——内含巧妙设计
问题 (1)CopyOnWriteArraySet是用Map实现的吗? (2)CopyOnWriteArraySet是有序的吗? (3)CopyOnWriteArraySet是并发安全的吗? (4)C ...
- 死磕 java集合之LinkedHashSet源码分析
问题 (1)LinkedHashSet的底层使用什么存储元素? (2)LinkedHashSet与HashSet有什么不同? (3)LinkedHashSet是有序的吗? (4)LinkedHashS ...
- 死磕 java集合之ConcurrentHashMap源码分析(三)
本章接着上两章,链接直达: 死磕 java集合之ConcurrentHashMap源码分析(一) 死磕 java集合之ConcurrentHashMap源码分析(二) 删除元素 删除元素跟添加元素一样 ...
- 死磕 java集合之ArrayDeque源码分析
问题 (1)什么是双端队列? (2)ArrayDeque是怎么实现双端队列的? (3)ArrayDeque是线程安全的吗? (4)ArrayDeque是有界的吗? 简介 双端队列是一种特殊的队列,它的 ...
- 死磕 java集合之LinkedList源码分析
问题 (1)LinkedList只是一个List吗? (2)LinkedList还有其它什么特性吗? (3)LinkedList为啥经常拿出来跟ArrayList比较? (4)我为什么把LinkedL ...
- 【死磕 Java 集合】— ConcurrentSkipListMap源码分析
转自:http://cmsblogs.com/?p=4773 [隐藏目录] 前情提要 简介 存储结构 源码分析 主要内部类 构造方法 添加元素 添加元素举例 删除元素 删除元素举例 查找元素 查找元素 ...
随机推荐
- main真正的形状函数
我们经常使用的像 int main()这种形式,但main长身体机能完全到底是什么样子? 以下这个main函数的形式可能有些出乎我们的意料: int main(int argc, char *argv ...
- cocos2d 简单的日常高仿酷跑游戏
1.第一个直接看看这个游戏看起来视频(GIF我们不能满足游戏展) 跑酷游戏最纠结的是地图.碰撞倒是简单,能够自己写或者使用box2d等物理引擎.跑酷游戏地图的特点就是随机性.可是随机中又有策划特意安排 ...
- Cytoscape画图初探
Cytoscape是一个做网络图的js插件.用起来非常方便,并且非常强大.这是它的站点:点击打开链接 使用它须要导入两个文件,一个是js文件,一个是css文件.官网上下载. 这里实现了一个功能.即从后 ...
- SSH-Struts(两)—调节器(ActionServlet)
第一部分介绍的博客Struts架构,下一节介绍中特定成分,这个博客是写Struts控制器ActionServlet. 扮演的角色 ActionServlet类是Struts的控制中心,全部来自于浏览器 ...
- 关于在 xmlSPY 出现的错误 DOCTYPE-EXternalID的名称必须既是SYSTEM 又是PUBLIC?(转)
最近我在做学习xml时,遇见一个问题,我本用的是2009 xml spy后来老是出现问题 ,就是不能通过,后来我上网查了一下,发现是以一问题,不管是在2006中还是在2009中,都会出现这样的问题,要 ...
- 一步一步的理解C++STL迭代器
一步一步的理解C++STL迭代器 "指针"对全部C/C++的程序猿来说,一点都不陌生. 在接触到C语言中的malloc函数和C++中的new函数后.我们也知道这两个函数返回的都是一 ...
- 开展project
正常的生活之路
相对刚走出学校的学生在其他行业工作,竞争力的薪酬,同时.并不断地不仅学习更新专业知识让你感到生活的充实,更满足了你那不让外人知的虚荣心.在刚出校门的几年中,你常常回头看看被你落在后面的同学们,在内心怜 ...
- Lucene40PostingWriter
控制freq和prox这两个文件的输出,比较简单. 默认skip interval这是16,max skip level这是10. 由源或使用可见VInt编码(而不是速度的传奇PForDelta). ...
- JavaScript--基于对象的脚本语言学习笔记(三)
事件处理器 1.一个数据校验表单的例程 <html> <head> <title>js练习</title> <meta http-equiv=&q ...
- javascript活动
在javascript倘若有知识的三个方面.事件的第一,流程,其次,事件处理,第三,事件对象.下面就我个人的理解,,分别讲述一下这三个方面的内容. 第一.事件流 事件流指的是事件依照一定的顺序触发.它 ...