Stack源码解析
我们从一个DEMO作为入口,了解Java的Stack的源码,代码如:
Stack<String> stack = new Stack<>();
stack.push("a"); // 入栈
stack.peek(); // 查询栈顶元素
stack.pop(); // 出栈
stack.empty(); // 判空
stack.search("a"); // 搜索元素
Stack类继承自Vector,基于数组实现,如图:


主要包含5个方法:入栈、出栈、查询栈顶、判空、查找元素,每个方法都有sychronized同步锁来保持同步,所以是线程安全的我们自上而下打开每个方法
入栈push()
入栈操作会先判断是否有足够的空间来存储新元素,如果没有的话那么要进行扩容
public E push(E item) {
addElement(item); // 添加元素
return item; // 返回当前元素
}
public synchronized void addElement(E obj) {
modCount++; // 修改次数+1
ensureCapacityHelper(elementCount + 1); // 确定数组容量是否足够,如果不够那么扩充数组
elementData[elementCount++] = obj; // 栈顶索引+1,将当前元素赋值到栈顶
}
private void ensureCapacityHelper(int minCapacity) {
if (minCapacity - elementData.length > 0) // 当前所需的容量 - 当前数组的容量 如果大于0,那么意味着超出了数组的容量
grow(minCapacity); // 超出则扩充数组容量
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 数组元素很大的时候,可能会超出预想导致内存溢出,需要限定数组的最大值;这里-8的目的是因为有的虚拟机在实现的时候会在数组头部预留一些空间
private void grow(int minCapacity) {
int oldCapacity = elementData.length; // 当前数组的容量
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); // 计算新的容量,如果有指定增长那么 + 指定增长,如果没有指定那么当前容量乘以2
if (newCapacity - minCapacity < 0) // 如果新容量还是不够
newCapacity = minCapacity; // 使用所需容量为新容量
if (newCapacity - MAX_ARRAY_SIZE > 0) // 如果新容量超过容量上限
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity); // 将原数组的数据拷贝到新的容器里,并替换原数组
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // 超出INT最大值则会变为负数,这里抛出内存溢出异常
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; // 所需容量大于上限,那么采用INT最大值,否则采用上限值
}
查询栈顶peek()
根据栈顶索引获取栈顶元素,但如果没有一个元素的情况下会抛出空栈异常
public synchronized E peek() {
int len = size(); // 当前栈的元素大小
if (len == 0) // 空栈抛出异常
throw new EmptyStackException();
return elementAt(len - 1); // 获取栈顶元素
}
public synchronized E elementAt(int index) {
if (index >= elementCount) { // 栈顶索引大于等于元素大小表示越界
throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
}
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index]; // 根据数组索引位置获取元素
}
出栈pop()
出栈只是把栈顶的元素置为null,让GC去回收。出栈之前会先获取栈顶元素,所有如果对空栈出栈,那么会抛出异常
public synchronized E pop() {
E obj;
int len = size(); // 获取当前元素大小
obj = peek(); // 获取栈顶元素
removeElementAt(len - 1); // 移除栈顶元素
return obj; // 返回被移除的元素
}
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); // 这里调用native方法,把被移除的元素之后的元素向前移动一位
}
elementCount--; // 元素数量 -1
elementData[elementCount] = null; // 置为null,让GC去销毁该元素
}
判空empty()
public boolean empty() {
return size() == 0; // 判断元素数量为0
}
查找元素search()
查找元素的时候从栈顶向下查找,如果有多个那么只匹配最上面的一个,没有则返回-1
public synchronized int search(Object o) {
int i = lastIndexOf(o); // 从栈顶向下搜索,如果匹配到则返回自上而下的索引,否则返回-1
if (i >= 0) {
return size() - i; // 计算自下而上的索引
}
return -1; // 没有找到
}
public synchronized int lastIndexOf(Object o) {
return lastIndexOf(o, elementCount-1); // 索引从栈顶开始
}
public synchronized int lastIndexOf(Object o, int index) {
if (index >= elementCount) // 越界检验
throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
if (o == null) { // 如果元素为null
for (int i = index; i >= 0; i--) // 自栈顶向下遍历
if (elementData[i]==null) // 如果存在 == null的,返回
return i;
} else { // 元素不为null
for (int i = index; i >= 0; i--) // 自栈顶向下遍历
if (o.equals(elementData[i])) // 元素相等的,返回
return i;
}
return -1; // 没有找到相等的元素
}
Stack源码解析的更多相关文章
- Java - Stack源码解析
Java提高篇(三一)-----Stack 在Java中Stack类表示后进先出(LIFO)的对象堆栈.栈是一种非常常见的数据结构,它采用典型的先进后出的操作方式完成的.每一个栈都包含一个栈顶,每次出 ...
- Java 集合系列07之 Stack详细介绍(源码解析)和使用示例
概要 学完Vector了之后,接下来我们开始学习Stack.Stack很简单,它继承于Vector.学习方式还是和之前一样,先对Stack有个整体认识,然后再学习它的源码:最后再通过实例来学会使用它. ...
- Java 集合系列 06 Stack详细介绍(源码解析)和使用示例
java 集合系列目录: Java 集合系列 01 总体框架 Java 集合系列 02 Collection架构 Java 集合系列 03 ArrayList详细介绍(源码解析)和使用示例 Java ...
- Java 集合系列Stack详细介绍(源码解析)和使用示例
Stack简介 Stack是栈.它的特性是:先进后出(FILO, First In Last Out). java工具包中的Stack是继承于Vector(矢量队列)的,由于Vector是通过数组实现 ...
- 【转】 Java 集合系列07之 Stack详细介绍(源码解析)和使用示例
概要 学完Vector了之后,接下来我们开始学习Stack.Stack很简单,它继承于Vector.学习方式还是和之前一样,先对Stack有个整体认识,然后再学习它的源码:最后再通过实例来学会使用它. ...
- Java Stack源码分析
Stack简介 Stack是栈.它的特性是:先进后出(FILO, First In Last Out).java工具包中的Stack是继承于Vector(矢量队列)的,由于Vector是通过数组实现的 ...
- 给jdk写注释系列之jdk1.6容器(10)-Stack&Vector源码解析
前面我们已经接触过几种数据结构了,有数组.链表.Hash表.红黑树(二叉查询树),今天再来看另外一种数据结构:栈. 什么是栈呢,我就不找它具体的定义了,直接举个例子,栈就相当于一个很窄的木桶 ...
- 源码解析-Volley(转自codeKK)
Volley 源码解析 本文为 Android 开源项目源码解析 中 Volley 部分项目地址:Volley,分析的版本:35ce778,Demo 地址:Volley Demo分析者:grumoon ...
- Java 集合系列05之 LinkedList详细介绍(源码解析)和使用示例
概要 前面,我们已经学习了ArrayList,并了解了fail-fast机制.这一章我们接着学习List的实现类——LinkedList.和学习ArrayList一样,接下来呢,我们先对Linked ...
随机推荐
- asp.net web api 跨域问题
缘起 以前在asp.net mvc时代,很少出现跨域问题 自从使用了asp.net web api + angular (1/2)之后,开始有跨域问题了. 简单普及下跨域: 我的理解是只要是前台页面与 ...
- vue-cli初始化一个项目
1,换成淘宝源: npm config set registry https://registry.npm.taobao.org/ 检查是否修改成功 npm config get registry 2 ...
- python学习笔记12-深浅拷贝
以上为浅拷贝. .copy()函数 赋值:数据完全共享(=赋值是在内存中指向同一个对象,如果是可变(mutable)类型,比如列表,修改其中一个,另一个必定改变 如果是不可变类型(immutable) ...
- 【liferay】6、可配置式cookie
问题提出 项目运行中,cookie的作用一般是起着一个不可或缺的权限控制或者认证的作用,但是如果是多系统交互,cookie是由别的系统生成,本系统对接的话,那么这个cookie就会 成为项目测试的一个 ...
- 刚破了潘金莲的身份信息(图片文字识别),win7、win10实测可用(免费下载)
刚破了潘金莲的身份信息(图片文字识别),win7.win10实测可用 效果如下: 证照,车牌.身份证.名片.营业执照 等图片文字均可识别 电脑版 本人出品 大小1.3MB 下载地址:https://p ...
- coursera 视频总是缓冲或者无法观看,有什么方法解决?
win7电脑,三个步骤: (1)修改hosts文件,地址如下: C:\Windows\System32\drivers\etc,然后以文本格式打开hosts. (2)将如下内容复制到文件末尾 52.8 ...
- ThreadLocal是否会引发内存泄露的分析 good
这篇文章,主要解决一下疑惑: 1. ThreadLocal.ThreadLocalMap中提到的弱引用,弱引用究竟会不会被回收? 2. 弱引用什么情况下回收? 3. JAVA的ThreadLocal和 ...
- JavaSE-序列化和反序列化
什么是序列化,什么时候要进行序列化? 序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化,将数据分解成字节流,以便存储在文件中或在网络上传输. 我们在对java对象进行IO流操作 ...
- SpringSecurity学习之基于数据库的用户认证
SpringSecurity给我们提供了一套最基本的认证方式,可是这种方式远远不能满足大多数系统的需求.不过好在SpringSecurity给我们预留了许多可扩展的接口给我们,我们可以基于这些接口实现 ...
- Node.js 安装及环境配置之 Windows 篇
一.安装环境 1.本机系统:Windows 10 企业版(64位)2.Node.js:node-v8.9.4-x64.msi(64位) 二.安装Node.js步骤 1.下载对应自己系统对应的 Node ...