源码阅读之Java栈的实现

简介: 栈是 Last-In-First-Out (后进先出)的线性表。对栈的操作主要有两个:入栈(push)和出栈(pop)。因此它也是一种操作受限的线性表。尽管如此,它在计算机中应用非常广泛,是一种非常基础的数据结构。

0x00 栈

栈是 Last-In-First-Out (后进先出)的线性表。对栈的操作主要有两个:入栈(push)和出栈(pop)。因此它也是一种操作受限的线性表。尽管如此,它在计算机中应用非常广泛,是一种非常基础的数据结构。

0x01 源码

从源码中可以看出栈也是一种非常简单的数据结构。栈的源码非常简洁,只有100多行代码。

public class Stack<E> extends Vector<E> {
     
    public Stack() {
    }

    //入栈操作
    public E push(E item) {
        addElement(item);

        return item;
    }

    //出栈操作
    public synchronized E pop() {
        E       obj;
        int     len = size();

        obj = peek();
        removeElementAt(len - 1);

        return obj;
    }

    //查看栈元素,不会删除
    public synchronized E peek() {
        int     len = size();

        if (len == 0)
            throw new EmptyStackException();
        return elementAt(len - 1);
    }

    //检查是否为空栈
    public boolean empty() {
        return size() == 0;
    }

    //查找元素,如果找到则返回从栈顶开始计数的位置,否则返回-1
    public synchronized int search(Object o) {
        int i = lastIndexOf(o);

        if (i >= 0) {
            return size() - i;
        }
        return -1;
    }

    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = 1224463164541339165L;
}
AI 代码解读

它继承于 Vector 类,这个跟前面讲的 ArrayList 是一样的,只不过 Vector 类方法是同步的,因此 Stack 也是线程安全的。

push

入栈

public E push(E item) {
    addElement(item);

    return item;
}
AI 代码解读

虽然此方法没有声明 synchronized,但内部调用一个 addElement 来实现入栈操作。这个操作方法是在父类中实现的,它被声明为线程安全的,因此它也是线程安全的。

public synchronized void addElement(E obj) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = obj;
}

private void ensureCapacityHelper(int minCapacity) {
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
//扩容方法
//这里跟 ArrayList 扩容算法有点不一样,ArrayList 一次是扩容为原来的1.5倍,Vector 默认扩容为原来的1倍
private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    elementData = Arrays.copyOf(elementData, newCapacity);
}
AI 代码解读

虽然 push 方法没有声明 synchronizedaddElement 方法中有。在这个方法里

  • 首先把 modCount 加 1,记录一次对数据结构的操作。
  • 然后检查数组容量是否足够,不够则扩容。
  • 最后把元素对象添加到数组末尾。

需要注意的是Vector的扩容策略是默认一次扩容为原来的1倍,这与ArrayList 一次扩容原来的1.5倍不同

pop

出栈

public synchronized E pop() {
    E       obj;
    int     len = size();

    obj = peek();
    removeElementAt(len - 1);

    return obj;
}
AI 代码解读

pop 方法被声明为 synchronized ,是线程安全的方法。它通过 peek 方法获取到栈顶元素对象,然后调用父类的 removeElementAt 方法把栈顶元素删除。

peek

查看栈顶元素

public synchronized E peek() {
    int     len = size();

    if (len == 0)
        throw new EmptyStackException();
    return elementAt(len - 1);
}
AI 代码解读

这个方法也是线程安全的。可以看出如果栈的大小为0时,执行 peek 方法会抛出 EmptyStackException 异常。

search

在栈中搜索元素

public synchronized int search(Object o) {
    int i = lastIndexOf(o);

    if (i >= 0) {
        return size() - i;
    }
    return -1;
}
AI 代码解读

继续查看父类代码

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) {//如果查找的元素是空的则遍历找到最接近栈的空元素
        for (int i = index; i >= 0; i--)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = index; i >= 0; i--)
            if (o.equals(elementData[i]))//通过equals方法来判断两个元素是否相同
                return i;
    }
    return -1;
}
AI 代码解读

在栈中查询一个元素需要遍历,时间复杂度为O(n)。

0x02 总结

栈是一种LIFO的数据结构,它基于 Vector 来实现,所有的方法都是线程安全的。入栈和出栈操作的时间复杂度为O(1),查找元素的时间复杂度为O(n)。

目录
相关文章
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
260 7
JUC并发—1.Java集合包底层源码剖析
本文主要对JDK中的集合包源码进行了剖析。
家政系统源码,java版本
这是一款基于SpringBoot后端框架、MySQL数据库及Uniapp移动端开发的家政预约上门服务系统。
家政系统源码,java版本
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
108 3
Java基于SaaS模式多租户ERP系统源码
ERP,全称 Enterprise Resource Planning 即企业资源计划。是一种集成化的管理软件系统,它通过信息技术手段,将企业的各个业务流程和资源管理进行整合,以提高企业的运营效率和管理水平,它是一种先进的企业管理理念和信息化管理系统。 适用于小微企业的 SaaS模式多租户ERP管理系统, 采用最新的技术栈开发, 让企业简单上云。专注于小微企业的应用需求,如企业基本的进销存、询价,报价, 采购、销售、MRP生产制造、品质管理、仓库库存管理、财务应收付款, OA办公单据、CRM等。
170 23
|
3月前
|
【源码】【Java并发】【ConcurrentHashMap】适合中学体质的ConcurrentHashMap
本文深入解析了ConcurrentHashMap的实现原理,涵盖JDK 7与JDK 8的区别、静态代码块、构造方法、put/get/remove核心方法等。JDK 8通过Node数组+链表/红黑树结构优化并发性能,采用CAS和synchronized实现高效锁机制。文章还详细讲解了hash计算、表初始化、扩容协助及计数更新等关键环节,帮助读者全面掌握ConcurrentHashMap的工作机制。
96 6
【源码】【Java并发】【ConcurrentHashMap】适合中学体质的ConcurrentHashMap
Java汽车租赁系统源码(含数据库脚本)
Java汽车租赁系统源码(含数据库脚本)
68 4
栈和队列【数据结构与算法Java】
栈和队列【数据结构与算法Java】
67 0
用栈实现队列(java数据结构与算法)
用栈实现队列(java数据结构与算法)
214 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问