前言

  前面分析了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篇(三)的更多相关文章

  1. Java集合类源码解析:Vector

    [学习笔记]转载 Java集合类源码解析:Vector   引言 之前的文章我们学习了一个集合类 ArrayList,今天讲它的一个兄弟 Vector.为什么说是它兄弟呢?因为从容器的构造来说,Vec ...

  2. Java集合类源码解析:HashMap (基于JDK1.8)

    目录 前言 HashMap的数据结构 深入源码 两个参数 成员变量 四个构造方法 插入数据的方法:put() 哈希函数:hash() 动态扩容:resize() 节点树化.红黑树的拆分 节点树化 红黑 ...

  3. java集合源码分析(三):ArrayList

    概述 在前文:java集合源码分析(二):List与AbstractList 和 java集合源码分析(一):Collection 与 AbstractCollection 中,我们大致了解了从 Co ...

  4. Java集合源码分析(三)LinkedList

    LinkedList简介 LinkedList是基于双向循环链表(从源码中可以很容易看出)实现的,除了可以当做链表来操作外,它还可以当做栈.队列和双端队列来使用. LinkedList同样是非线程安全 ...

  5. java集合类源码学习三——ArrayList

    ArrayList无疑是java集合类中的一个巨头,而且或许是使用最多的集合类.ArrayList继承自AbstractList抽象类,实现了List<E>, RandomAccess, ...

  6. Java集合源码分析(三)Vevtor和Stack

    前言 前面写了一篇关于的是LinkedList的除了它的数据结构稍微有一点复杂之外,其他的都很好理解的.这一篇讲的可能大家在开发中很少去用到.但是有的时候也可能是会用到的! 注意在学习这一篇之前,需要 ...

  7. Java集合类源码解析:ArrayList

    目录 前言 源码解析 基本成员变量 添加元素 查询元素 修改元素 删除元素 为什么用 "transient" 修饰数组变量 总结 前言 今天学习一个Java集合类使用最多的类 Ar ...

  8. Java集合类源码解析:AbstractList

    今天学习Java集合类中的一个抽象类,AbstractList. 初识AbstractList AbstractList 是一个抽象类,实现了List<E>接口,是隶属于Java集合框架中 ...

  9. java集合类源码学习二

    我们查看Collection接口的hierarchy时候,可以看到AbstractCollection<E>这样一个抽象类,它实现了Collection接口的部分方法,Collection ...

  10. Java集合类源码分析

    常用类及源码分析 集合类 原理分析 Collection   List   Vector 扩充容量的方法 ensureCapacityHelper很多方法都加入了synchronized同步语句,来保 ...

随机推荐

  1. mysql设计表结构数据类型的选择

    选择合适的数据类型 在使用MySQL创建数据表的时候会遇到一个问题,如何为字段选择合适的数据类型.比如创建一个员工信息表,每个字段都可以用很多种类型来定义, int,char,float等等. cha ...

  2. http请求设置setConnectTimeout()方法超时无响应

    相信非常多小伙伴在写 HttpURLConnection中都设置了setConnectTimeout()方法.目的就是在网络不好的情况下超时返回 然而我们设置的setConnectTimeout()并 ...

  3. 剑指offer 面试36题

    面试36题: 题:二叉搜索树与双向链表 题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 解题思路一:由于输入的一个二叉搜索树, ...

  4. vim之可视化

    参考文档:http://blog.csdn.net/ii1245712564/article/details/46960387 先梳理关键知识,方便查阅 v(小v):进入可视化 V(大V):进入可视行 ...

  5. spark学习(1)--ubuntu14.04集群搭建、配置(jdk)

    环境:ubuntu14.04 jdk-8u161-linux-x64.tar.gz 1.文本模式桌面模式切换 ctrl+alt+F6 切换到文本模式 ctrl + alt +F7 /输入命令start ...

  6. JPEGView——专业、免费、开源的图像浏览器

    虽叫JPEGView,它不仅支持jpeg图像格式,主流的图像格式它都支持. 试一试你就知道它有多强大了.

  7. layer满屏/禁止最大化最小化 可以做选择框使用

    1.layer弹窗最大化 var index=layer.open(); layer.full(index); 2.layer禁止最大化最小化 layer.open( [ type:2, title: ...

  8. 大数据架构之:Storm

         Storm是一个免费开源.分布式.高容错的实时计算系统,Twitter开发贡献给社区的.Storm令持续不断的流计算变得容易,弥补了Hadoop批处理所不能满足的实时要求. Storm经常用 ...

  9. 建议40:深入掌握ConfigParser

    # -*- coding:utf-8 -*- ''' 1.getboolean() 根据一定的规则将配置项的值转换为布尔值 getboolean() 的真值规则: 0.no.false 和off 都会 ...

  10. 0801 RESTAPI设计,DRF 序列化

    1.内容回顾    1.restframework serializer(序列化)的简单使用                QuereySet([obj,obj,obj])  -->  JSON ...