Java集合类源码解析:Vector
引言
之前的文章我们学习了一个集合类 arraylist,今天讲它的一个兄弟 vector。
为什么说是它兄弟呢?因为从容器的构造来说,vector 简直就是 arraylist 的翻版,也是基于数组的数据结构,不同的是,vector的每个方法都加了 synchronized 修饰符,是线程安全的。
类声明
用idea打开 vector 的源码,不难发现,它的类声明跟 arraylist 一模一样,都是继承了abstractlist,并且都实现了randomaccess接口,遍历元素用for循环的效率要优于迭代器。
* @author lee boynton * @author jonathan payne * @see collection * @see linkedlist * @since jdk1.0 */ public class vector<e> extends abstractlist<e> implements list<e>, randomaccess, cloneable, java.io.serializable
值得说明的是,从注释上来看,vector 是 jdk1.0版本就引进的,属于最古老的集合类的那一批,而arraylist是 1.2才引进的,所以说,vector才是哥哥,arraylist是小弟,哈哈~~~~
基本变量和构造函数
基本变量
vector 的基本变量有四个,分别是:
- 底层数组
protected object[] elementdata;
- 数组元素个数
protected int elementcount;
- 增长的容量大小,如果这个值小于或等于0,扩容时会扩大 2 倍,
capacityincrement
- 最大容量
private static final int max_array_size = integer.max_value - 8;
构造函数
//创建初识容量为10的数组,增长量0 public vector() { this(10); } //创建初识容量可变的数组,增长量为0 public vector(int initialcapacity) { this(initialcapacity, 0); } //创建初识容量可变的数组,可设置增长量 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(collection<? extends e> c) { elementdata = c.toarray(); elementcount = elementdata.length; // c.toarray might (incorrectly) not return object[] (see 6260652) if (elementdata.getclass() != object[].class) elementdata = arrays.copyof(elementdata, elementcount, object[].class); }
看的出来,vector的构造器和成员变量和arraylist大同小异。
成员方法
扩容
vector 与 arraylist 虽然很类似,但在扩容大小这方面还是有区别的,arraylist 默认扩容后的大小为原容量 的1.5倍,而vector则是先判断增长量大小,如果是非正数,那就扩大为原来的2倍,看一下它的扩容方法:
//参数是最小需要的容量 private void grow(int mincapacity) { // overflow-conscious code int oldcapacity = elementdata.length; //如果增长量不大于0,扩容为2倍大小 //一般默认创建的容器都是不传增长量的,所以默认增长量是0,也就是默认直接扩容两倍 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); } private static int hugecapacity(int mincapacity) { if (mincapacity < 0) // overflow throw new outofmemoryerror(); return (mincapacity > max_array_size) ? integer.max_value : max_array_size; }
添加
vector的添加方法都是加上 synchronized
关键字的,并且添加前检测容量,判断是否扩容:
//加入元素到数组结尾,同步的 public synchronized boolean add(e e) { modcount++; //检测容量 ensurecapacityhelper(elementcount + 1); elementdata[elementcount++] = e; return true; } //检测容量大小,超过数组长度就做扩容 private void ensurecapacityhelper(int mincapacity) { // overflow-conscious code if (mincapacity - elementdata.length > 0) grow(mincapacity); } public void add(int index, e element) { insertelementat(element, index); } //插入对应索引的元素 public synchronized void insertelementat(e obj, int index) { modcount++; if (index > elementcount) { throw new arrayindexoutofboundsexception(index + " > " + elementcount); } ensurecapacityhelper(elementcount + 1); //插入元素前,把其索引后面的元素统一后移一位 system.arraycopy(elementdata, index, elementdata, index + 1, elementcount - index); elementdata[index] = obj; elementcount++; } public synchronized void addelement(e obj) { modcount++; //保证容量足够 ensurecapacityhelper(elementcount + 1); //直接设置最后一个元素的数据 elementdata[elementcount++] = obj; } //添加整个集合 public synchronized boolean addall(collection<? extends e> c) { modcount++; //把集合转为数组对象 object[] a = c.toarray(); int numnew = a.length; ensurecapacityhelper(elementcount + numnew); //直接复制集合元素到数组后面 system.arraycopy(a, 0, elementdata, elementcount, numnew); elementcount += numnew; return numnew != 0; } //在对应的索引处插入一个集合 public synchronized boolean addall(int index, collection<? extends e> c) { modcount++; if (index < 0 || index > elementcount) throw new arrayindexoutofboundsexception(index); object[] a = c.toarray(); int numnew = a.length; ensurecapacityhelper(elementcount + numnew); //计算要移动多少个元素 int nummoved = elementcount - index; if (nummoved > 0) //把插入位置后面的元素后移这么多位 system.arraycopy(elementdata, index, elementdata, index + numnew, nummoved); //复制元素数组 system.arraycopy(a, 0, elementdata, index, numnew); elementcount += numnew; return numnew != 0; }
vector的添加方法代码不是很复杂,跟arraylist 一样,本质上都是对数组做插入数据的操作,不同的是,方法都加了synchronized 修饰,所以,它的添加方法都是线程安全的。
其他操作元素的方法也是这样的套路,这里不打算一一列举了,因为都跟arraylist 差不多,另外,vector 比 arraylist 多了一个迭代方法
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"); } }; }
返回的是一个enumeration 接口对象,大概也是个容器接口,没用过,不说太多。
vector 对比 arraylist
最后,总结一下 vector 和 arraylist 的对比吧。
相同点:
-
底层都是基于数组的结构,默认容量都是10;
-
都实现了randomaccess 接口,支持随机访问;
-
都有扩容机制;
区别:
-
vector 的方法有做同步操作,是属于线程安全的,而arraylist 是非线程安全的;
-
vector默认情况下扩容后的大小为原来的2倍,而arraylist 是1.5倍;
-
vector 比 arraylist 多了一种迭代器 enumeration;
虽然vector相较arraylist做了同步的处理,但这样也影响了效率,因为每次调用方法都要获取锁,所以,一般情况下,对集合的线程安全没有需求的话,推荐使用 arraylist。
版权保护:本文为转载文章,原文地址:
推荐阅读
-
Mybaits 源码解析 (五)----- 面试源码系列:Mapper接口底层原理(为什么Mapper不用写实现类就能访问到数据库?)
-
java拓展集合工具类CollectionUtils
-
死磕 java同步系列之Phaser源码解析
-
Mybaits 源码解析 (八)----- 全网最详细,没有之一:结果集 ResultSet 自动映射成实体类对象(上篇)
-
Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析
-
Java中的容器(集合)之ArrayList源码解析
-
java 抽象类和接口的区别详细解析
-
死磕 java同步系列之CyclicBarrier源码解析——有图有真相
-
Java中的容器(集合)之HashMap源码解析
-
[五]类加载机制双亲委派机制 底层代码实现原理 源码分析 java类加载双亲委派机制是如何实现的