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 [隐藏目录] 前情提要 简介 存储结构 源码分析 主要内部类 构造方法 添加元素 添加元素举例 删除元素 删除元素举例 查找元素 查找元素 ...
随机推荐
- spring 整合quartz的方式——简单介绍
一.继承QuartzJobBean,重写executeInternal方法 <bean name="statQuartzJob" class="org.spring ...
- Java多线程中wait, notify and notifyAll的使用
本文为翻译文章,原文地址:http://www.journaldev.com/1037/java-thread-wait-notify-and-notifyall-example 在Java的Obje ...
- (大数据工程师学习路径)第二步 Vim编辑器----Vim快速入门
vim模式介绍 以下介绍内容来自维基百科Vim 从vi演生出来的Vim具有多种模式,这种独特的设计容易使初学者产生混淆.几乎所有的编辑器都会有插入和执行命令两种模式,并且大多数的编辑器使用了与Vim截 ...
- 关于接收POST请求 $GLOBALS['HTTP_RAW_POST_DATA']
总是产生变量包含有原始的 POST 数据.否则,此变量仅在碰到未识别 MIME 类型的数据时产生.不过,访问原始 POST 数据的更好方法是 php://input.$HTTP_RAW_POST_DA ...
- ASP.NET MVC Boilerplate简介
ASP.NET MVC Boilerplate简介 ASP.NET MVC Boilerplate是专业的ASP.NET MVC模版用来创建安全.快速.强壮和适应性强的Web应用或站点.它在微软默认M ...
- DevExpress XtraReports 入门一 创建 Hello World 报表
原文:DevExpress XtraReports 入门一 创建 Hello World 报表 本文只是为了帮助初次接触或是需要DevExpress XtraReports报表的人群使用的,为了帮助更 ...
- Swift——(三)Swift神奇的下划线
在Swift在.有许多神奇的下划线,在这里,我们将看到神奇的汇总,我希望能够帮助其他很多学习Swift朋友. @Author: twlkyao转载或者引用请保留此行. 1.格式化数字字面量 通 ...
- java多线程(同步和死锁,生产者和消费者问题)
首先我们来看看同步与死锁: 所谓死锁.这是A有banana,B有apple. A至B说:你把apple对我来说,,我会banana给你. B至A说:你把banana对我来说,,我会apple给你. 可 ...
- linux_环境变量设置 utf-8
echo $LANG 显示编码 : en_US.UTF-8 英文urf8有时显示程序输出是? 解决方法: vim ~/.bashrc 最后一行追加: export LANG=zh_CN.UTF- ...
- duplicate symbol _*** in:
duplicate symbol _kReachabilityChangedNotification in: 问题出在同一个文件被引用两次,在项目中找到引用的地方,删掉对应的引用