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同步语句,来保 ...
随机推荐
- CSS3随意记录
1.注释 注释语法:/* 注解注释内容 */ 2.带有透明度 rgba(255,0,0,0.5);rgba(0,255,0,0.5);rgba(0,0,255,0.5); 0.5就带有透明的,介于0和 ...
- XSL-FO Page Layout
Simple Layout Let's take a look at the simple page layout that we saw earlier in the course. The sim ...
- Django 之 权限系统(组件)
参考: http://www.cnblogs.com/yuanchenqi/articles/7609586.html
- 笔记:zookeeper Hello World
下载zookeeper-3.4.6 , 试用了一下 standlone 启动 ./bin/zkServer.sh start 注: Usage: ./bin/zkServer.sh {start|st ...
- make编译四
书写命令 每条规则中的命令和操作系统 Shell 的命令行是一致的. make 会按顺序一条一条的执行命令, 每条命令的开头必须以[Tab]键开头, 除非,命令是紧跟在依赖规则后面的分号后的.在命令行 ...
- (4.19)深入理解SQLSERVER的日志链
您真的理解了SQLSERVER的日志链了吗? 转自:https://www.cnblogs.com/lyhabc/p/3460272.html 先感谢宋沄剑给本人指点迷津,还有郭忠辉童鞋今天在QQ群里 ...
- HAProxy的访问控制
HAProxy的ACL用于实现基于请求报文首部.响应报文的内容或其他的环境状态信息来做出转发决策,这大大增强了其配置弹性,其配置法则通常分为两步,首先去定义ACL,即定义一个测试条件,而后在条件得到满 ...
- DD DT DL标签
我们平时常用的是< ul>< li>标签,不过dd.dt标签也蛮不错,特别是发布程序的时候功能模块列表什么的可以使用它来排版. < dl>< /dl>& ...
- UI控件之UICollectionView
UICollectionView:集合视图,是iOS6.0后出现的,与UITableView类似,优势在于可以灵活的布局cell UICollectionViewLayout:布局类,抽象类,一般定义 ...
- 主攻ASP.NET MVC4.0之重生:使用反射获取Controller的ActionResult
示例代码 public ActionResult TypeOfForName() { Type typeinfo = typeof(CustomerClassController); //typeof ...