本来今天是想看一下Stack的源码的,但是在看到Stack的父类结构时
1 | 复制代码public class Stack<E> extends Vector<E> |
我想到了我之前还没怎么看过Vector的源码,甚至乎还很少用,我之前对他的了解大概就是停留在跟ArrayList很相似,是线程安全的ArrayList,先总结下ArrayList和Vector的不同之处,然后带着结论去看源码,找原因
ArrayList和Vector对比:
- 相同之处:
+ 都是基于数组
+ 都支持随机访问
+ 默认容量都是10
+ 都支持动态扩容
+ 都支持fail—fast机制
- 不同之处:
+ Vector历史比ArrayList久远,Vector是jdk1.0,ArrayList是jdk1.2
+ Vector是线程安全的,ArrayList线程不安全
+ Vector动态扩容默认扩容两倍,ArrayList是1.5倍
底层数据结构
Vector底层是基于数组实现的
1 | 复制代码protected Object[] elementData; |
ArrayList底层数据结构也是数组
1 | 复制代码private static final Object[] |
其他相关属性
1 | 复制代码 //数组中元素数量 |
构造方法
无参构造,数组容量默认是10
1 | 复制代码 //无参构造,数组容量默认是10 |
ArrayList默认数组容量也是10
1 | 复制代码 //默认容量 |
Vcetor其他构造方法:
指定容量和增长量构造
1 | 复制代码 //创建指定容量大小的数组,设置增长量。 |
指定容量和增长量为0的构造:
1 | 复制代码 public Vector(int initialCapacity) { |
传入指定集合构造
1 | 复制代码 public Vector(Collection<? extends E> c) { |
扩容机制
在了解添加元素之前我们需要理清Vector的扩容机制是怎样的,其实跟ArrayList的扩容机制也很相似
1.计算最小容量:
最小容量 = 当前数组元素数量 + 1,此举的目的就是判断是否需要扩容,最小容量就是相当于成功添加了一个元素后的新的数组元素数量,如果这个新的数组元素数量大于数组长度,那么肯定需要扩容
1 | 复制代码 private void ensureCapacityHelper(int minCapacity) { |
2.传入最小容量开始扩容:
- 如果当前数组的增长量 > 0则新数组容量 = 旧数组容量 + 增长量
- 否则,则新数组容量 = 2 * 旧数组容量
- 求出新数组容量后,如果新数组容量 < 最小容量,那么新数组容量 = 最小容量
- 如果新数组容量 > 最大数组容量,则新数组容量 = 整数最大值
1 | 复制代码 //最小数组容量 |
4.扩容实际:数组复制和移动
1 | 复制代码 public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { |
ArrayList的扩容机制其实和Vector很相似,至少原理是一致的,但是在扩容大小上不一样
因为ArrayList没有增长量这一概念,所以ArrayList默认扩容1.5倍
1 | 复制代码 private void grow(int minCapacity) { |
ArrayList扩容流程:
添加元素
数组尾部添加指定元素
可以看到添加方法上带有synchronized同步关键字,保证了在添加元素时的线程安全,但是也会带来获取锁和释放锁的效率问题
1 | 复制代码 public synchronized void addElement(E obj) { |
指定位置添加指定元素
1 | 复制代码 public synchronized void insertElementAt(E obj, int index) { |
添加指定集合
1 | 复制代码 public synchronized boolean addAll(Collection<? extends E> c) { |
删除元素
删除指定下标元素
1 | 复制代码 public synchronized E remove(int index) { |
删除指定元素
1 | 复制代码 public synchronized boolean removeElement(Object obj) { |
删除所有元素
1 | 复制代码 public synchronized void removeAllElements() { |
删除指定范围的元素
1 | 复制代码 protected synchronized void removeRange(int fromIndex, int toIndex) { |
查询
从指定下标开始找到指定元素第一次出现的下标
从前往后找
1 | 复制代码 public synchronized int indexOf(Object o, int index) { |
从后往前找
1 | 复制代码 public synchronized int lastIndexOf(Object o, int index) { |
返回指定下标的元素
1 | 复制代码 E elementData(int index) { |
是否包含指定元素
1 | 复制代码 //看没有该下标 |
迭代器
迭代器和ArrayList相比是差不多的,包括实现也是,可以参考ArrayList源码分析
本文转载自: 掘金