Vector类也是List集合的一种类型,源码分析将与ArrayList类对比进行。
目录
1、构造方法
2、扩容机制
3、遍历删除时的陷阱、迭代器、分割器
4、其他方法
1、构造方法
源码分析如下:
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
/** 对象数组 */
protected Object[] elementData;
/** Vector集合的大小 */
protected int elementCount;
/** 容量步进 */
protected int capacityIncrement;
/**
* Vector集合有下面四种构造器:无参,指定容量大小,指定容量大小+容量步进,指定集合
**/
public Vector() {this(10);} //①
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) { //④
// 保证传入集合非null,否则报NPE
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);
}
}
小结一下:
与ArrayList集合相比,Vector集合同样:
- 继承了AbstractList类,实现了List接口, RandomAccess接口, Cloneable接口,Serializable接口;
- 底层也维护了一个对象数组Object[]来存储元素,且元素是有序、可重复的存储;
- 构造器也有无参,指定容量大小,指定集合对象等入参形式。
不同的是:
- Vector集合构造器多了一个重载(即第③种),入参多了容量步进capacityIncrement,该参数用于扩容计算;
- Vector集合是直接在构造器内进行指定默认容量大小10,而ArrayList集合在使用add()方法添加元素时才初始化默认容量为10。
2、扩容机制
Vector集合通过add()方法添加元素时,会触发自动扩容操作,源码分析如下:
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
/**
* 以add(E e)方法为例,Vector集合扩容的关键步骤如下:
* add()方法是一个synchronized方法
**/
public synchronized boolean add(E e) {
modCount++;
// 1.添加元素到数组前先进行判断是否需要扩容
ensureCapacityHelper(elementCount + 1);
// 6.将该元素存放在数组上,size自加1标识Vector集合中元素添加了1个
elementData[elementCount++] = e;
return true;
}
/** 2.超过数组大小,通过grow()方法扩容 */
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/** 数组最大容量 */
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
// 3.扩容计算方式:步进>0 —— oldCapacity*2 ;步进<=0 —— oldCapacity + capacityIncrement 。
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
// 4.扩容后对象数组大小出现以下两种情况,则重新赋值扩容后对象数组大小
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 5.通过数组拷贝方式,实现自动扩容
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;
}
/**
* add(int index, E e):是将元素插入到指定位置,也需要扩容判断
* 也是一个synchronized方法
**/
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++;
}
/**
* addAll():两个集合求并集,同样需要扩容判断
* 也是一个synchronized方法
**/
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;
}
/**
* addElement():向Vector集合追加内容
* 也是一个synchronized方法
**/
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
/**
* setSize():重置Vector集合大小
* 也是一个synchronized方法
**/
public synchronized void setSize(int newSize) {
modCount++;
if (newSize > elementCount) {
ensureCapacityHelper(newSize);
} else {
for (int i = newSize ; i < elementCount ; i++) {
elementData[i] = null;
}
}
elementCount = newSize;
}
}
小结一下:
- Vector集合将默认容量10放在了构造器中,其余的关键扩容步骤与ArrayList集合是一样的,只是扩容计算公式不同而已 —— Vector集合按照两倍A 或者 A+B的方式扩容,ArrayList集合按照1.5倍扩容!
- 与ArrayList集合相比,Vector集合的add()方法、addAll()方法、setSize()方法、addElement()方法均是同步的,因此多线程环境中进行相关操作是线程安全的!
3、遍历删除时的陷阱、迭代器、分割器
遍历删除时的陷阱:
与ArrayList集合相比,Vector集合自身也有两个删除的方法:remove(int index)、remove(Object o),除了remove()是synchronized的,实现删除逻辑与ArrayList集合也是一样的!同样的,foreach遍历使用集合自身删除方法时,仍然存在ConcurrentModificationException异常,原因也是Iterator源码中的next()方法中存在 checkForComodification()方法,它会检查预期修改次数expectedModCount 和实际修改次数modCount 是否一致,不一致会报并发修改异常。因此,建议使用Iterator的remove()方法遍历删除!!!
迭代器:
迭代器Iterator和列表迭代器ListIterator的使用也适用于Vector集合,除了相关操作是synchronized的,实现逻辑均是一致的。
在Vector集合遍历循环时容易引发ConcurrentModificationException异常的方法有:(modCount变量存在的地方都有可能引发并发修改异常!!)
- trimToSize()、setSize()、clear()、add()、addAll()、remove()等方法用在遍历时;
- Java8新增的方法:forEach()、removeIf()、sort()、replaceAll()等等。
分割器Spliterator:
Vector集合的分割器Spliterator,类似ArrayList集合的分割器,源码逻辑实现类似。
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
@Override
public Spliterator<E> spliterator() {
return new VectorSpliterator<>(this, null, 0, -1, 0);
}
/** Similar to ArrayList Spliterator */
static final class VectorSpliterator<E> implements Spliterator<E> {
private final Vector<E> list;
private Object[] array;
private int index; // current index, modified on advance/split
private int fence; // -1 until used; then one past last index
private int expectedModCount; // initialized when fence set
/** Create new spliterator covering the given range */
VectorSpliterator(Vector<E> list, Object[] array, int origin, int fence,
int expectedModCount) {
this.list = list;
this.array = array;
this.index = origin;
this.fence = fence;
this.expectedModCount = expectedModCount;
}
private int getFence() {...;}
public Spliterator<E> trySplit() {...;}
public boolean tryAdvance(Consumer<? super E> action) {...;}
public void forEachRemaining(Consumer<? super E> action) {...;}
public long estimateSize() {return (long) (getFence() - index);}
public int characteristics() {
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
}
}
4、其他方法
Vector集合其余的操作方法,大多数都是synchronized的,并发操作是线程安全的!!!
public class Vector<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
// 将Vector集合的元素拷贝到指定数组中
public synchronized void copyInto(Object[] anArray) {System.arraycopy(elementData, 0, anArray, 0, elementCount);}
// Vector集合当前容量
public synchronized int capacity() {return elementData.length;}
// Vector集合的大小
public synchronized int size() {return elementCount;}
// 集合判空
public synchronized boolean isEmpty() {return elementCount == 0;}
// 判断集合是否包含指定对象
public boolean contains(Object o) {return indexOf(o, 0) >= 0;}
// 是一种浅克隆,不会将原集合的元素拷贝到新的集合
public synchronized Object clone() {...;}
// 重写equals方法
public synchronized boolean equals(Object o) {return super.equals(o);}
// 重写hashCode方法
public synchronized int hashCode() {return super.hashCode();}
// 重写toString方法
public synchronized String toString() {return super.toString();}
// Vector集合转对象数组
public synchronized Object[] toArray() {return Arrays.copyOf(elementData, elementCount);}
// Vector集合转泛型数组,由运行时确定数组类型
public synchronized <T> T[] toArray(T[] a) {...;}
// 查找元素在集合中的位置(顺序查找)
public synchronized int indexOf(Object o, int index) {...; return -1;}
// 查找元素在集合中的位置(倒序查找)
public synchronized int lastIndexOf(Object o, int index) {...; return -1;}
// 返回Vector集合的第一个元素
public synchronized E firstElement() {...; return elementData(0);}
// 返回Vector集合最后的一个元素
public synchronized E lastElement() {...; return elementData(elementCount - 1);}
// 返回Vector集合中指定索引位置的元素
public synchronized E elementAt(int index) {...; return elementData(index);}
// 在Vector集合中指定位置修改元素
public synchronized void setElementAt(E obj, int index) {...; elementData[index] = obj;}
// 从指定范围,截取生成新的子集合
public synchronized List<E> subList(int fromIndex, int toIndex) {
return Collections.synchronizedList(super.subList(fromIndex, toIndex), this);
}
}
小结
Vector集合作为List集合的实现类,从底层实现的元素存储,自动扩容机制,迭代器和列表迭代器,到分割器等与ArrayList集合最为相似了。而最大的不同就是线程安全问题,从以上的源码不难发现,Vector集合的方法几乎都是同步方法,能保证并发操作集合时是安全的。但同步方法锁住的是整个方法,高并发场景中会显得并发操作效率低的问题,因此优先推荐使用J.U.T包下的 CopyOnWriteArrayList集合来操作List集合类型的数据。不积硅步无以至千里,点滴付出终将有所收获,共同进步 ~