Stack源码解析

我们从一个DEMO作为入口,了解Java的Stack的源码,代码如:

1 Stack<String> stack = new Stack<>();
2 stack.push("a"); // 入栈
3 stack.peek(); // 查询栈顶元素
4 stack.pop(); // 出栈
5 stack.empty(); // 判空
6 stack.search("a"); // 搜索元素

Stack类继承自Vector,基于数组实现,如图:

主要包含5个方法:入栈、出栈、查询栈顶、判空、查找元素,每个方法都有sychronized同步锁来保持同步,所以是线程安全的我们自上而下打开每个方法

入栈push()

入栈操作会先判断是否有足够的空间来存储新元素,如果没有的话那么要进行扩容

 1 public E push(E item) {
 2     addElement(item); // 添加元素
 3     return item; // 返回当前元素
 4 }
 5 
 6 public synchronized void addElement(E obj) {
 7     modCount++; // 修改次数+1
 8     ensureCapacityHelper(elementCount + 1); // 确定数组容量是否足够,如果不够那么扩充数组
 9     elementData[elementCount++] = obj; // 栈顶索引+1,将当前元素赋值到栈顶
10 }
11 
12 private void ensureCapacityHelper(int minCapacity) {
13     if (minCapacity - elementData.length > 0) // 当前所需的容量 - 当前数组的容量 如果大于0,那么意味着超出了数组的容量
14         grow(minCapacity); // 超出则扩充数组容量
15 }
16 
17 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 数组元素很大的时候,可能会超出预想导致内存溢出,需要限定数组的最大值;这里-8的目的是因为有的虚拟机在实现的时候会在数组头部预留一些空间
18 
19 private void grow(int minCapacity) {
20     int oldCapacity = elementData.length; // 当前数组的容量
21     int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); // 计算新的容量,如果有指定增长那么 + 指定增长,如果没有指定那么当前容量乘以2
22     if (newCapacity - minCapacity < 0) // 如果新容量还是不够
23         newCapacity = minCapacity; // 使用所需容量为新容量
24     if (newCapacity - MAX_ARRAY_SIZE > 0) // 如果新容量超过容量上限
25         newCapacity = hugeCapacity(minCapacity);
26     elementData = Arrays.copyOf(elementData, newCapacity); // 将原数组的数据拷贝到新的容器里,并替换原数组
27 }
28 
29 private static int hugeCapacity(int minCapacity) {
30     if (minCapacity < 0) // 超出INT最大值则会变为负数,这里抛出内存溢出异常
31         throw new OutOfMemoryError();
32     return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; // 所需容量大于上限,那么采用INT最大值,否则采用上限值
33

 

查询栈顶peek()

根据栈顶索引获取栈顶元素,但如果没有一个元素的情况下会抛出空栈异常

 1 public synchronized E peek() {
 2     int len = size(); // 当前栈的元素大小
 3     if (len == 0)  // 空栈抛出异常
 4         throw new EmptyStackException();
 5     return elementAt(len - 1); // 获取栈顶元素
 6 }
 7 
 8 public synchronized E elementAt(int index) {
 9     if (index >= elementCount) { // 栈顶索引大于等于元素大小表示越界
10         throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
11     }
12     return elementData(index);
13 }
14 
15 E elementData(int index) {
16     return (E) elementData[index]; // 根据数组索引位置获取元素
17 }

 

出栈pop()

出栈只是把栈顶的元素置为null,让GC去回收。出栈之前会先获取栈顶元素,所有如果对空栈出栈,那么会抛出异常

 1 public synchronized E pop() {
 2     E       obj;
 3     int     len = size(); // 获取当前元素大小
 4     obj = peek(); // 获取栈顶元素
 5     removeElementAt(len - 1); // 移除栈顶元素
 6     return obj; // 返回被移除的元素
 7 }
 8 
 9 public synchronized void removeElementAt(int index) {
10     modCount++; // 统计修改次数
11     if (index >= elementCount) { // 越界校验
12         throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
13     } else if (index < 0) { // 越界校验
14         throw new ArrayIndexOutOfBoundsException(index);
15     }
16     int j = elementCount - index - 1;
17     if (j > 0) { 
18         System.arraycopy(elementData, index + 1, elementData, index, j); // 这里调用native方法,把被移除的元素之后的元素向前移动一位
19     }
20     elementCount--; // 元素数量 -1
21     elementData[elementCount] = null; // 置为null,让GC去销毁该元素
22 }

 

判空empty()

1 public boolean empty() {
2     return size() == 0; // 判断元素数量为0
3 }

 

查找元素search()

查找元素的时候从栈顶向下查找,如果有多个那么只匹配最上面的一个,没有则返回-1

 1 public synchronized int search(Object o) {
 2     int i = lastIndexOf(o); // 从栈顶向下搜索,如果匹配到则返回自上而下的索引,否则返回-1
 3     if (i >= 0) {
 4         return size() - i; // 计算自下而上的索引
 5     }
 6     return -1; // 没有找到
 7 }
 8 
 9 public synchronized int lastIndexOf(Object o) {
10     return lastIndexOf(o, elementCount-1); // 索引从栈顶开始
11 }
12 
13 public synchronized int lastIndexOf(Object o, int index) {
14     if (index >= elementCount) // 越界检验
15         throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
16     if (o == null) { // 如果元素为null
17         for (int i = index; i >= 0; i--) // 自栈顶向下遍历
18             if (elementData[i]==null) // 如果存在 == null的,返回
19                 return i;
20     } else { // 元素不为null
21         for (int i = index; i >= 0; i--) // 自栈顶向下遍历
22             if (o.equals(elementData[i])) // 元素相等的,返回
23                 return i;
24     }
25     return -1; // 没有找到相等的元素
26 }

 

转载于:https://www.cnblogs.com/lay2017/p/10757306.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值