Java小白集合源码的学习系列:Vector
Vector源码学习
前文传送门:
Java小白集合源码的学习系列:LinkedList
Java小白集合源码的学习系列:ArrayList
Vector是JDK1.0中的集合,是集合中的老大哥,其中大部分的方法都被synchronized关键字所修饰,与ArrayList和LinkedList不同,它是线程安全的(关于线程安全,之后学习再做系统总结)。但是随着一系列的更新迭代,它的缺点渐渐暴露:如方法名字太长,实现接口时出现了许多重复多余的方法等等。
从JDK1.2开始,Vector类被改进以实现List接口,让它成为Java集合框架的一员,如果不需要线程安全,建议使用ArrayList,效率更高。
Vector继承体系
还是按照惯例,先看看它的继承图,当然这张图是基于JDK1.8的。
- 可以看出来它和
ArrayList
一样,继承了AbstractList
,实现List
接口。 - 实现了
RandomAccess
接口,支持随机访问。 - 实现了
Cloneable
接口,实现了克隆的功能。 - 实现了
Serializable
接口,支持序列化。
Vector核心源码
基本属性
//存储元素的数组
protected Object[] elementData;
//元素个数
protected int elementCount;
//该值决定了增长机制的不同
protected int capacityIncrement;
private static final long serialVersionUID = -2767605614048989439L;
构造器
我们可以得出结论:Vector
的底层也是基于数组实现的,但是这些属性和我们之前提到的ArrayList
有什么不同之处呢?我们继续向下看它所提供的几个构造器:
//两个参数,创建initialCapacity大小的数组,并为capacityIncrement赋值
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
//带一个参数,调用public Vector(int initialCapacity, int capacityIncrement)
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
//无参构造器,调用Vector(int initialCapacity)
public Vector() {
this(10);
}
//传入集合
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
//类型判断
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
我们可以发现:
initialCapacity
代表的是数组的容量,我们可以指定容量,不指定默认为10。capacityIncrement
从字面上看,就可以知道它代表的是容量增量,意味着这个值将会影响之后的扩容,可以指定,不指定默认为0。
扩容机制
那么我们继续来看看它的扩容机制,是否可以验证我们的说法:
基本上的部分,都是和ArrayList类似,我们直接截取有差异的部分:
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
//如果增量大于0,新容量 = 原容量 + 增量
//如果增量不大于0,新容量 = 原容量*2
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);
}
其他的部分就不做分析了,之前讲的很详细,可以看看前面的文章。我们需要关注的是:
- 如果指定增量(增量>0),那么每次在扩容的时候,新容量就是在原容量的基础上加上指定增量。
- 如果没有指定增量,那么每次在扩容的时候,新容量默认变成原容量的两倍。
Enumeration
概述
说起迭代器,我们总是第一个想到的就是Iterator
,而再Iterator是在JDK1.2的时候诞生的,用于取代JDK1.0版本的唯一迭代器Enumeration
。官方对它的解释是这样的:
An object that implements the Enumeration interface generates a series of elements, one at a time. Successive calls to the nextElement method return successive elements of the series.
我用拙劣的英语试着翻译一下:实现Enumeration这个接口的对象呢,将会生成一系列的元素,生成的时候是一个一个生成的,通过调用nextElement
这个方法,就可以返回这个系列里所有的连续元素。
今天我们励志做个光荣的官方文档搬运工!
Methods are provided to enumerate through the elements of a vector, the keys of a hashtable, and the values in a hashtable. Enumerations are also used to specify the input streams to a SequenceInputStream.
这段的意思也很明白:Enumeration接口为Vector的元素,hashtable的键和值提供了枚举的方法,它也被运用到指定SequenceInputStream的输入流中。我们暂时只需要知道,Vector类中,有一种方法能够产生Eumeration对象就完事了。其他的我们后面会进行总结。
接下来这段话相当关键!官方文档中用了大写的NOTE:
NOTE:The functionality of this interface is duplicated by the Iterator interface. In addition, Iterator adds an optional remove operation, and has shorter method names. New implementations should consider using Iterator in preference to Enumeration.
大致的意思就是:现在这个方法呢,不太适应潮流了,那个年代用起来挺不错,现在需要年轻一辈来代替了。这个新一代的产物就是Iterator,它复制了Enumeration的功能,并且增加可选的remove操作,而且提供了更简短的命名。官方仿佛在嬉皮笑脸对你说:亲,这边建议你迭代器尽量用Iterator哟。
但是尽管如此,我们还需需要了解以下它的基本操作,毕竟以后可能还是会见到。
源码描述
//Enumeration接口
public interface Enumeration<E> {
//判断是否还有更多的元素
boolean hasMoreElements();
//没有下一个元素就报错,有就返回
E nextElement();
}
//Vector中的elements方法对接口的实现
public Enumeration<E> elements() {
//通过匿名内部类实现接口
return new Enumeration<E>() {
int count = 0;
public boolean hasMoreElements() {
return count < elementCount;
}
public E nextElement() {
synchronized (Vector.this) {
if (count < elementCount) {
return elementData(count++);
}
}
throw new NoSuchElementException("Vector Enumeration");
}
};
}
具体操作
Vector<String> v = new Vector<>();
v.add("天");
v.add("乔");
v.add("巴");
v.add("夏");
//利用vector对象产生迭代器对象
Enumeration<String> e = v.elements();
//判断后边是否还有元素
while(e.hasMoreElements()){
//挪动指针指向下一个元素
System.out.print(e.nextElement()+" ");
}
//天 乔 巴 夏
Vector总结
- 底层基于数组,可以实现动态扩增,支持根据索引快速访问。
- 如果没有指定容量,默认为10。如果没有指定增量,默认为0。
- 扩容时,如果增量>0,则新容量=指定增量+原容量;如果增量<=0,则新容量为原容量的两倍。(注意,Vector里也有实现确定容量的方法ensureCapacity)
- 线程安全,如在创建迭代器之后的任何时间对结构进行修改,除了迭代器本身的remove和add外,都会抛出ConcurrentModification异常。所以,Vector通过
synchronized
关键字实现线程同步。可以参考:https://blog.csdn.net/yjclsx/article/details/85283169
本文若有叙述不当之处,还望各位评论区加以批评指正,谢谢。
参考资料:JDK1.8官方文档
Java小白集合源码的学习系列:Vector的更多相关文章
- Java小白集合源码的学习系列:LinkedList
目录 LinkedList 源码学习 LinkedList继承体系 LinkedList核心源码 Deque相关操作 总结 LinkedList 源码学习 前文传送门:Java小白集合源码的学习系列: ...
- Java小白集合源码的学习系列:ArrayList
ArrayList源码学习 本文基于JDK1.8版本,对集合中的巨头ArrayList做一定的源码学习,将会参考大量资料,在文章后面都将会给出参考文章链接,本文用以巩固学习知识. ArrayList的 ...
- 【JDK1.8】 Java小白的源码学习系列:HashMap
目录 Java小白的源码学习系列:HashMap 官方文档解读 基本数据结构 基本源码解读 基本成员变量 构造器 巧妙的tableSizeFor put方法 巧妙的hash方法 JDK1.8的putV ...
- JAVA常用集合源码解析系列-ArrayList源码解析(基于JDK8)
文章系作者原创,如有转载请注明出处,如有雷同,那就雷同吧~(who care!) 一.写在前面 这是源码分析计划的第一篇,博主准备把一些常用的集合源码过一遍,比如:ArrayList.HashMap及 ...
- java集合 源码解析 学习手册
学习路线: http://www.cnblogs.com/skywang12345/ 总结 1 总体框架 2 Collection架构 3 ArrayList详细介绍(源码解析)和使用示例 4 fai ...
- Java基础——集合源码解析 List List 接口
今天我们来学习集合的第一大体系 List. List 是一个接口,定义了一组元素是有序的.可重复的集合. List 继承自 Collection,较之 Collection,List 还添加了以下操作 ...
- Java并发包源码学习系列:JDK1.8的ConcurrentHashMap源码解析
目录 为什么要使用ConcurrentHashMap? ConcurrentHashMap的结构特点 Java8之前 Java8之后 基本常量 重要成员变量 构造方法 tableSizeFor put ...
- Java并发包源码学习系列:阻塞队列实现之ArrayBlockingQueue源码解析
目录 ArrayBlockingQueue概述 类图结构及重要字段 构造器 出队和入队操作 入队enqueue 出队dequeue 阻塞式操作 E take() 阻塞式获取 void put(E e) ...
- Java并发包源码学习系列:阻塞队列实现之LinkedBlockingQueue源码解析
目录 LinkedBlockingQueue概述 类图结构及重要字段 构造器 出队和入队操作 入队enqueue 出队dequeue 阻塞式操作 E take() 阻塞式获取 void put(E e ...
随机推荐
- hibernate中因双向依赖而造成的json怪相--springmvc项目
简单说一下Jackson 如果想要详细了解一下Jackson,可以去其github上的项目主页查看其版本情况以及各项功能.除此以外,需要格外提一下Jackson的版本问题.Jackson目前主流版本有 ...
- Navicat for MySQL 使用SSH方式链接远程数据库
第一步:ssh部分: 端口号:22 用户名为:在xshell中用来登录服务器的账号密码 第二步: 端口:3306 账号密码:在MySQL中的登录账号密码
- CF351E Jeff and Permutation
CF351E Jeff and Permutation 贪心好题 考虑每个对能否最小化贡献和 先不考虑绝对值相同情况 发现,对于a,b假设|a|<|b|,那么有无贡献只和b的正负有关!如果a在b ...
- linux 运行处理者
如同前面建议的, 当内核收到一个中断, 所有的注册的处理者被调用. 一个共享的处理者 必须能够在它需要的处理的中断和其他设备产生的中断之间区分. 使用 shared=1 选项来加载 short 安装了 ...
- [Ctsc2014]图的分割
[Ctsc2014]图的分割 阅读理解好题 翻译一下: M(C)就是C这个诱导子图最小生成树最大边权 结论: 按照w进行sort,如果满足w<=Ci,Cj表示u,v的连通块的诱导子图 并且Ci! ...
- 改变this指向
fn.call(obj,参数,参数): call(函数执行过程中this指向,后面的参数就是原函数的参数列表) : 函数下的一个内置方法,当我们申明一个函数的时候,这个函数下就会有一个默认的方法,ca ...
- sublimeText 3使用教程
工欲善利其事必先利其器,sublime作为一款轻量.便捷的编译工具,集成了很多插件,功能强大,深受大家的喜爱.掌握好sublime的具体用法,必会为你的工作带来极大的便利!好了,闲话不多说了,下面开始 ...
- linux zookeeper开机启动
1.在zkEnv.sh中指定当前用户jdk环境变量 export JAVA_HOME=/usr/local/src/jdk1.7.0_55/ 2.在/etc/rc.d/init.d文件夹下创建zook ...
- Github Pages 无法调用 node_modules 文件夹的解决方案
今天写一个demo,用npm安装的前端库,然后想在github的pages上展示出来 发布到github后,发现node_modules文件夹下的js无法调用 google解决方案:新增一个名字为.n ...
- Visual Studio Team Services使用教程【4】:默认团队checkin权限修改
2017.4.23之后建议朋友看下面的帖子 TFS2017 & VSTS 实战(繁体中文视频) Visual Studio Team Services(VSTS)与敏捷开发ALM实战关键报告( ...