Java-集合类源码List篇(三)
前言
前面分析了ArrayList和LinkedList的实现,分别是基于数组和双向链表的List实现。但看之前那张图,还有两个实现类,一个是Vector,另一个是Stack,接下里一起走进它们的源码世界吧!
4. Vector
Vector跟ArrayList比较相似,继承实现的类或者接口也都是一样的,都是继承自AbstractList,同时底层也是基于数组来实现的。
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
4.1 Vector成员变量
/**
* 数组来保存集合中的元素
*/
protected Object[] elementData; /**
* 集合size
*/
protected int elementCount; /**
* 增长步长
*/
protected int capacityIncrement;
Vector既然是基于数组来实现的,那么肯定有一个数组的成员变量elementData,返回集合中当前元素的个数elementCount。与ArrayList不同的是增加了一个增长步长,我们知道在ArrayList中,每次增长是上一次的容量的1.5倍,而Vector中则是如果指定了capacityIncrement且该值为正整数,则每次需要扩容时的容量增长为该数值。
4.2 Vector访问元素
/**
* 添加元素
*/
public synchronized boolean add(E e) {
modCount++;
//判断是否需要扩容
ensureCapacityHelper(elementCount + 1);
//将元素添加至指定位置
elementData[elementCount++] = e;
return true;
}
看到上述方法是否很熟悉,没错,它其实跟ArrayList的添加元素方法基本差不多。唯一不同的就是该方法加了synchronized关键字,该关键字的意思就是访问该方法时需要获取到对象锁的线程方能访问。这就是Vector的线程安全访问机制,通过为每个方法添加synchronized关键字的方法达到在多线程对集合类进行操作时,能够线程安全访问。其它的基本与ArrayList无异。
5. Stack
看Vector的成员变量的时候,发现都是protected修饰的,所以是可以被子类直接访问的。
public
class Stack<E> extends Vector<E>
的确在Stack中是没有另外成员变量的,与Vector相比只不过增加了对栈操作的方法,所以Stack是基于数组的线程安全的栈实现集合。
Stack是一个基于LILO(后进先出)的栈的实现,它初始化的时候也是一个空的栈。可以看下他的构造函数:
/**
* Creates an empty Stack.
*/
public Stack() {
}
5.1 Stack的成员方法
|
public E push(E item); |
添加元素(入栈) |
|
public synchronized E pop(); |
移除元素(出栈) |
|
public synchronized E peek(); |
返回栈顶元素 |
|
public synchronized int search(Object o); |
查找元素 |
看到上述的成员方法,就知道它的方法同Vector一样都是同步的,所以它也是一种线程安全的实现。上面5个方法中,push是没有synchronized修饰的,而其他四个方法都是被synchronized修饰,这个是为什么呢?我们来看下push的源码实现:
public E push(E item) {
//调用Vector中的实现
addElement(item);
return item;
}
/**
* Vector中的addElement实现
* @param obj
*/
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
所以我们知道,push()方法其实调用的还是父类Vector的实现,所以就没有加synchronized修饰也能达到同步的效果啦!
再来看下search()方法实现:
public synchronized int search(Object o) {
int i = lastIndexOf(o);
if (i >= 0) {
return size() - i;
}
return -1;
}
返回对象在栈中的位置,下标从1开始,栈顶元素为1。
其中数组的最后一位元素即为栈顶元素,search方法返回的是离栈顶最近的item与栈顶之间的距离!
在JDK中,有如下语句:
* <p>A more complete and consistent set of LIFO stack operations is
* provided by the {@link Deque} interface and its implementations, which
* should be used in preference to this class. For example:
* <pre> {@code
* Deque<Integer> stack = new ArrayDeque<Integer>();}</pre>
*
如果想要实现一个LIFO的基于数组栈实现的话,JDK中提供了ArrayDeque是应该优先考虑的。事实上ArrayDeque同LinkedList一样,都是可以作为LIFO(后进先出)的栈实现,同时也是可以作为FIFO(先进先出)的队列实现。那么就有个问题了:
为什么同样基于数组实现,Stack只能实现栈而ArrayDeque却可以作为栈和队列的实现呢?
要想实现FIFO的队列实现,那么必须满足能够在队列首部出队列,尾部进队列,就是要两端能够操作。

假定有以上数组,那么如果基于栈实现的话,则只需要维护该数组的尾端,出栈移除最大索引元素,size--,入栈则只需要判断size+1与length的大小,看是否需要扩容。如果要做到队首进行出队列,队尾入队列的操作,则每次出队列后,为保持数组空间的连续性都需要将全部元素往前移动一位,那么效率上则不是一种很理想的实现。
事实上,ArrayDeque是虽然也是采用基于数组实现的,而它的则增加了逻辑上的循环,通过增加head和tail使其变成了“循环数组”。所以在ArrayDeque中尾部指向索引tail不一定比首部索引head更大。至于具体实现就到后面Deque的接口实现类部分再详述啦!
小结
本篇中,主要是分析了基于的数组的集合实现类Vector和Stack,下面小结一下:
Stack与LinkedList用作堆栈时异同:
1.实现机制:Stack是基于数组实现的,LinkedList是基于链表实现的。
2.线程安全:Stack是在方法上进行了同步访问,LinkedList则没有,若需要同步,可通过Collections的同步方法实现。
Vector与ArrayList区别:
1.线程安全:Vector是在方法上进行了同步访问,ArrayList则没有,若需要同步,可通过Collections的同步方法实现。
2.成员变量:Vector增加了一个capacityIncrement成员属性,在扩容时该变量指定情况则直接增加相应步长容量。ArrayList则是增加约1.5倍容量。
经过三篇的篇幅,List接口的下的常用集合我们已经分析完啦!
Java-集合类源码List篇(三)的更多相关文章
- Java集合类源码解析:Vector
[学习笔记]转载 Java集合类源码解析:Vector 引言 之前的文章我们学习了一个集合类 ArrayList,今天讲它的一个兄弟 Vector.为什么说是它兄弟呢?因为从容器的构造来说,Vec ...
- Java集合类源码解析:HashMap (基于JDK1.8)
目录 前言 HashMap的数据结构 深入源码 两个参数 成员变量 四个构造方法 插入数据的方法:put() 哈希函数:hash() 动态扩容:resize() 节点树化.红黑树的拆分 节点树化 红黑 ...
- java集合源码分析(三):ArrayList
概述 在前文:java集合源码分析(二):List与AbstractList 和 java集合源码分析(一):Collection 与 AbstractCollection 中,我们大致了解了从 Co ...
- Java集合源码分析(三)LinkedList
LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全 ...
- java集合类源码学习三——ArrayList
ArrayList无疑是java集合类中的一个巨头,而且或许是使用最多的集合类.ArrayList继承自AbstractList抽象类,实现了List<E>, RandomAccess, ...
- Java集合源码分析(三)Vevtor和Stack
前言 前面写了一篇关于的是LinkedList的除了它的数据结构稍微有一点复杂之外,其他的都很好理解的.这一篇讲的可能大家在开发中很少去用到.但是有的时候也可能是会用到的! 注意在学习这一篇之前,需要 ...
- Java集合类源码解析:ArrayList
目录 前言 源码解析 基本成员变量 添加元素 查询元素 修改元素 删除元素 为什么用 "transient" 修饰数组变量 总结 前言 今天学习一个Java集合类使用最多的类 Ar ...
- Java集合类源码解析:AbstractList
今天学习Java集合类中的一个抽象类,AbstractList. 初识AbstractList AbstractList 是一个抽象类,实现了List<E>接口,是隶属于Java集合框架中 ...
- java集合类源码学习二
我们查看Collection接口的hierarchy时候,可以看到AbstractCollection<E>这样一个抽象类,它实现了Collection接口的部分方法,Collection ...
- Java集合类源码分析
常用类及源码分析 集合类 原理分析 Collection List Vector 扩充容量的方法 ensureCapacityHelper很多方法都加入了synchronized同步语句,来保 ...
随机推荐
- 九度OJ 1357:疯狂地Jobdu序列 (数字特性)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:715 解决:263 题目描述: 阳仔作为OJ的数据管理员,每一周的题目录入都让其很抓狂,因为题目不是他出的,他控制不了出题的速度--在等题目 ...
- redis集群报错,(error) MOVED 15495 127.0.0.1:7003
节点会对命令请求进行分析和key的slot计算,并且会查找这个命令所要处理的键所在的槽.如果要查找的哈希槽正好就由接收到命令的节点负责处理, 那么节点就直接执行这个命令. 另一方面, 如果所查 ...
- 剖析与优化 Go 的 web 应用
https://mp.weixin.qq.com/s/HDsbZLOK3h8-XjejvPH2sA https://studygolang.com/articles/12685
- Socket_leaks open socket #5024 left in connection
open socket left in connection http://mailman.nginx.org/pipermail/nginx/2012-September/035627.html D ...
- NSCache类的简单介绍
最近看SDWebImage,里面的内存缓存用到了NSCache这个类,由于以前没有使用过,特此记录学习一下. NSCache NSCache是苹果官方提供的缓存类,用法和NSMutableDicton ...
- 阻止element组件中的<el-input/>的粘贴功能
需求: 阻止element组件中的<el-input/>的粘贴功能 实现思路: <el-input/>组件是由外层<div>和内层的<input>组成的 ...
- 我的Android进阶之旅------>Android中查看应用签名信息
一.查看自己的证书签名信息 如上一篇文章<我的Android进阶之旅------>Android中制作和查看自定义的Debug版本Android签名证书>地址:http://blog ...
- TLS and SSL
SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层.SSL通过互相认证.使用数字签名确保完整性.使用加密确保私密性,以实现客户 ...
- 玩转git版本控制软件
一.git的基本介绍 1.什么是git? git是个开源的分布式版本控制软件,用以有效.高速的处理从很小到非常大的项目版本管理.说白了就是个版本控制软件 2.git的使用方法 git软件是通过命令来实 ...
- java上机
package wordcont; import java.io.BufferedReader; import java.io.FileReader; import java.util.ArrayLi ...