Vector底层结构和源码分析(JDK1.8)
参考视频:韩顺平Java集合
- Vector 类的定义说明:
- Vector 的底层也是一个对象数组,
protected Object[] elementData;
- Vector 是线程同步的,即线程安全,Vectoe 类的操作方法带有
synchronized
关键字:public synchronized boolean add(E var1) { ++this.modCount; this.ensureCapacityHelper(this.elementCount + 1); this.elementData[this.elementCount++] = var1; return true; }
- 在开发中,需要线程同步安全时,考虑使用 Vector。
源码示例
未指定初始容量
- 测试源码
- 观察调用空参构造器,创建 Vector 的实例的细节(第一次扩容)
- 观察第一次添加元素(不扩容)
- 观察第十一次添加元素(第二次扩容)
@Test public void test1(){ List list = new Vector(); for (int i = 1; i <= 20; i++) { list.add(i); } }
空参创建 Vector(初次扩容)
- 调用空参构造器:实际上在该构造器中调用了有参构造器,并传入参数10。
capacityIncrement
参数用于指定每次扩容时的容量增量。当Vector的容量不足以容纳新添加的元素时,它会根据 capacityIncrement 的值来增加容量。如果 capacityIncrement 大于0,则之后每次扩容的容量为当前的容量加上capacityIncrement;如果 capacityIncrement 小于或等于0,则每次扩容的容量为当前容量的一倍。- 也就是创建了一个长度为 10 的数组。(此时elementData.length=10)
第一次添加元素(不扩容)
- 调用
add()
方法添加元素“1”到 Vector 集合中: - 数组修改次数+1,
ensureCapacityHelper()
确认当前数组是否有所需要的容量大小(elementCount+1=1
);如果没有则进行扩容,否则不动。 - (注意:在 Vector 中使用变量 elementCount 记录元素个数,而不是 size)
ensureCapacityHelper()
判断当前数组容量(elementData.length
)是否满足所需容量 (var1
)- 此时
elementData.length=10
,满足所需容量var1=1
的需求,所以不扩容。 - 回到原方法:在 elementCount 处存储要添加的元素 var1。并且 elementCount+1。
第 11 次添加元素(第二次扩容)
- 添加元素“11”到 Vector 数组中。
- 此时数组容量(elementData.length=10)已经不满足所需容量==(var1=11)==了,所以需要扩容,进入
grow()
方法中
- var2=当前数组长度==(此时elementData.length=10)==
- var3=要扩容的目标长度(如果
capacityIncrement
>0,则扩容为原始长度+capacityIncrement
;若=0,则扩容为原始长度的两倍) - 此时 capacityIncrement 没有值,所以 var3=10+10=20
- 判断目标扩容的长度是否超过数组的范围。
- Arrays.copyOf() 作用:创建一个 var 3 容量大小的数组(20),并将原数组中的元素拷贝至新数组,赋值给 elementData。
- 至此,就完成了数组的扩容。
- 回到 add 方法的主逻辑中:在 elementCount 处存储要添加的元素 var1。并且 elementCount+1。
指定初始容量
- 测试源码
- 观察调有参构造器,创建 Vector 的实例的细节(第一次扩容)
- 观察第一次添加元素(不扩容)
- 观察第九次添加元素(第二次扩容)
@Test public void test1(){ List list = new Vector(8); for (int i = 1; i <= 20; i++) { list.add(i); } }
调用有参构造器,指定初始容量(第一次扩容)
- 调用有参构造器,其内部调用了构造器,并为 capacityIncrement 赋值为 0。
- 那么此时构造器创建了一个长度为 8 的数组。==(elementData.length=8) ==
第一次添加数据(不扩容)
- 记录修改数组的次数+1
- 确认当前数组是否含有 elementCount+1=1 个大小的容量。如果没有则扩容。
- 检查当前数组的容量==(element.length=8)是否满足所需容量的大小(var1=1)==。
- 显然,此时容量是够的,不需要扩容,跳过
grow()
- 回到 add() 的主逻辑中:在 elementCount 处存储要添加的元素 var1。并且 elementCount+1=1。
第九次添加数据(第二次扩容)
- 此时需要的容量 (elementCount+1=9),进入
ensureCapacityHelper()
中。
- 判断当前数组长度 (elementData.length=8) 是否满足所需容量长度==(var1=9)==
- 显然,不够。所以需要扩容,进入
grow()
中 - var2=原始数组容量(8)
- var3=需要扩容到的目标容量长度,此时 capacityIncrement=0,所以扩容至原始长度的两倍(16)
- 检查目标长度 var3是否满足需求 var1
- 检查目标长度是否超过数组范围上限。
- Arrays.copyOf() 作用:创建一个 var3 容量大小的数组(16),并将原数组中的元素拷贝至新数组,赋值给 elementData。
- 至此,数组的扩容完成。回到 add() 主逻辑:在 elementCount 处存储要添加的元素 var1。并且 elementCount+1=9。