前言
阅读 Java 版本为 1.8.0.25。
栈(Stack) 和 队列(Queue) 应该是大家非常熟悉的数据结构了。
Java 中有 栈(Stack) 的具体类, 队列(Queue) 只定义了接口,当然所有实现了这个接口的类都可以当作一个队列使用。
首先是最基本的定义:
栈(stack ),一种遵循先进后出(FILO—First-In/Last-Out)原则的线性存储结构。
队列(queue),一种遵循先进先出(FIFO—first in first out)原则的线性存储结构。
栈和队列的实现方式也是不止一种,主要有:顺序存储结构(数组底层)和链式存储结构(链表)。主要区别就是元素在实际物理空间的存放位置,也就是内存是否连续。
栈(Stack) 这个类继承自 Vector ,底层用数组实现,是 JDK1.0 时代的产物,官方已经不推荐使用了。
队列(Queue) 的话,JDK1.6 开始声明了 Deque(double ended queue )双向队列接口 ,双向队列同时具备栈和队列的功能。
所以现在选择在 java 中使用 栈和队列 的话,推荐选择实现了 Deque 的
-
首选是 ArrayDeque ,其次是 LinkedList ,当然这两个都不是线程安全的。
-
对于线程安全的需求,JDK 提供了 BlockingQueue 阻塞队列以及双向队列,这也是一个非常重要的接口。(本文不介绍,重新开一篇。)
然后,选择 ArrayDeque 的具体原因后面详细介绍。
学习方式为,将源码以及相关类拷贝至自定义包内,进行注释添加,代码请移步:
https://github.com/qianwei4712/JDK1.8.0.25-read/blob/master/src/main/java/java/util/ArrayDeque.java
其中包含了 Stack、Queue、Deque、ArrayDeque 类或接口的注释。
Stack
刚刚已经提到,栈(Stack) 这个类继承自 Vector ,底层用数组实现。
可以参考下以前写的 Vector 源码分析 。
因为 Vector 在方法上添加了 synchronized ,以达到线程安全的目的,不过 JVM 级别的 synchronized 特别消耗资源,已不被 Java 官方推荐使用。
所以继承自它的 Stack 更不可能被推荐使用。并且 Stack 代码很少,底层有兴趣转 Vector 源码解读吧,包括它的扩容,构造等。
Stack 的方法:
方法名 | 返回类型 | 说明 |
---|---|---|
empty | boolean | 判断是否为空 |
peek | E | 只返回栈顶端的元素,不弹出该元素(空栈会抛出异常) |
pop | E | 弹出栈顶的元素 |
push | E | 将元素压入栈,并返回 |
search | int | 返回最靠近顶端的目标元素到顶端的距离(调用 lastIndexOf) |
Queue & Deque
java 中 Queue(单向队列) 是个接口,设计了队列基础方法,实际代码要看实现类。
Deque(双向队列) 继承 Queue 在原有队列方法基础上,增加反向队列方法,也设计了栈的基础方法。
所以,我一般都是使用双向队列实现类的,毕竟有一个类能实现两个效果,多省事。。。。。
java中最常见的队列是 LinkedList ,底层用链表实现,顺便打个广告,有兴趣可以看看我以前写的 linkedList 的源码
可以参考下以前写的 LinkedList 源码分析 。
接口官方注释中,要求了一些抛出异常的情形,不是每个接口都有这四个约束,具体请自行查阅 JDK:
- 若违反容量限制,抛出 IllegalStateException
- 若传入的类型和泛型不兼容,抛出 ClassCastException
- 如果指定元素为 null,并且这个队列不允许为 null,抛出 NullPointerException
- 若传入元素的某些属性阻止压入,那么抛出 IllegalArgumentException
Queue(单向队列) 基础方法:
功能 | 异常系列 | 增强系列 |
---|---|---|
添加 |