Vector与ArrayList十分相似,只是ArrayList【读我】是线程不安全的,而Vector的实现是线程安全的。现在一起来看看它的实现吧!
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
可以发现Vector继承的类和实现的接口与ArrayList一模一样。
由iterator()
和listIterator(int)
方法返回的迭代器是fail-fast
的:如果列表在迭代器创建之后的任何时间被结构化地修改,除了通过迭代器自己的remove或add方法之外,迭代器将会抛出ConcurrentModificationException。 因此,面对并发修改,迭代器将快速而干净地失败,而不是在未来未确定的时间冒着任意的非确定性行为。由elements()
返回的Enumerations
不是fail-fast
的。
Vector是同步的。 如果不需要线程安全的实现,建议使用ArrayList代替Vector。
/*
* 顾名思义,此变量用于存储Vector的数据,同时我们也知道了Vector底层也是数组实现的。
* Vector的容量是此数组缓冲区的长度,并且至少足够大以包含所有向量的元素。
* 注:Vector中最后一个元素后面的任何数组元素都为空。
*/
protected Object[] elementData;
/*
* 该Vector对象中有效组件的数量。 组件elementData[0]至elementData[elementCount-1]是实际项目。
*/
protected int elementCount;
/*
* 当Vector的大小大于其容量时,Vector的容量自动增加的量。
* 如果容量增量小于或等于零,则每次需要增长时,向量的容量将加倍。
*/
protected int capacityIncrement;
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;
}
通过构造方法我们知道如果使用无参构造方法默认初始化容量大小为10,且每次扩容时向量的容量将加倍(因为capacityIncrement<=0)。指定的初始化容量必须大于等于0,否则抛异常。
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
// c.toArray也许不会返回Object[]类型
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
按照集合的迭代器返回的顺序,构造一个包含指定集合元素的向量。
public synchronized void copyInto(Object[] anArray) {
System.arraycopy(elementData, 0, anArray, 0, elementCount);
}
将此Vector中的组件复制到指定的数组中。Vector中索引k处的项目被复制到anArray的索引k处。可以发现此方法使用synchronized
修饰了,所以这是线程安全的,我们可以发现其实Vector中大量方法大部分是使用它完成同步的,所以Vector的效率其实是不高的。
public synchronized void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (elementCount < oldCapacity) {
elementData = Arrays.copyOf(elementData, elementCount);
}
}
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
修改该Vector的容量为Vector的当前大小。底层通过新建一个大小为Vector大小的数组并将原数据拷贝过去来实现,所以elementData
变化了。
此方法用于Vector的扩容。在与检查容量相关方法中都需要使用此方法。
private void grow(int minCapacity) {
//minCapacity表示所需的最小容量
int oldCapacity = elementData.length;
//通过此行代码可以知道如果capacityIncrement<=0,则双倍扩容。
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
//如果capacityIncrement扩容后的新容量依旧小于minCapacity,则新容量就是minCapacity
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
//扩容后的新容量大于MAX_ARRAY_SIZE,我们需要重新计算容量
//MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
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的容量是否满足要求(minCapacity表示所需的最小容量),过小则使用grow方法进行扩容。
public synchronized void ensureCapacity(int minCapacity) {
if (minCapacity > 0) {
modCount++;
ensureCapacityHelper(minCapacity);
}
}
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity); //扩容
}
设置Vector的大小。如果新的大小大于当前大小,则新的项目将添加到Vector的末尾。 如果新的大小小于当前尺寸,则将newSize后的所有元素置为null。
public synchronized void setSize(int newSize) {
modCount++;
if (newSize > elementCount) {
//新大小大于当前大小,需要确认一下容量,判断是否需要扩容
ensureCapacityHelper(newSize);
} else {
for (int i = newSize ; i < elementCount ; i++) {
elementData[i] = null;//将newSize后的所有元素置为null
}
}
elementCount = newSize;
}
返回当前Vector的容量。
public synchronized int capacity() {
return elementData.length;
}
返回当前Vector包含项目的数目。
public synchronized int size() {
return elementCount;
}
判断当前Vector是否为空,为空返回true,否则返回false。
public synchronized boolean isEmpty() {
return elementCount == 0;
}
返回Vector中元素的枚举。返回的Enumeration对象将生成Vector中的所有项。产生的第一项索引为0,第二项索引为1,依此类推。在遍历过程中我们可以之间进行添加和删除操作,说明其不提供fail-fast机制
。
返回Vector中指定元素的第一次出现位置的索引,如果此向量不包含元素,则返回-1。与此方法类似的还有lastIndexOf
,只是此方法返回最后一次出现位置的索引。
public int indexOf(Object o) {
return indexOf(o, 0);
}
public synchronized int indexOf(Object o, int index) {
if (o == null) {
for (int i = index ; i < elementCount ; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = index ; i < elementCount ; i++)
if (o.equals(elementData[i]))
//返回第一个符合条件的索引
return i;
}
//找不到返回-1
return -1;
}
返回指定索引的元素。与其类似的方法有firstElement
和 lastElement
,返回第一个元素和最后一个元素,还有get(int index)
。
设置指定索引的元素。与之类似的有set(int index, E element)
。
删除指定索引的元素。removeElement(Object obj)
方法调用此方法实现删除操作(先找位置再删除),remove(Object o)
方法调用removeElement实现。
public synchronized void removeElementAt(int index) {
modCount++;
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
}
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
//计算index后面的元素个数
int j = elementCount - index - 1;
if (j > 0) {
//将index后面的元素复制到前一位
System.arraycopy(elementData, index + 1, elementData, index, j);
}
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */
}
删除指定索引位置的元素,返回旧值。
传入一个谓词,满足指定条件的元素。
public static void main(String[] args) {
Vector<Integer> vector = new Vector<Integer> (100);
vector.add(1);vector.add(2);
vector.add(3);vector.add(4);
vector.add(5);vector.add(6);
vector.add(7);vector.add(8);
boolean b = vector.removeIf(n -> n % 2 == 0);
Iterator<Integer> iterator = vector.iterator();
while (iterator.hasNext()){
System.out.print(iterator.next() + " ");
}
}
//1 3 5 7
删除Vector所有元素。底层将Vector中的所有元素置为null,一切就交给GC了。clear
方法使用此方法完成。
往指定索引中插入元素。Vector的add(int index, E element)
方法调用此方法实现。
public synchronized void insertElementAt(E obj, int index) {
modCount++;
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " > " + elementCount);
}
//插入元素前需要确认还有容量
ensureCapacityHelper(elementCount + 1);
//将index后(包括index)的元素后移一位
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
//设置index索引上的值为新值
elementData[index] = obj;
elementCount++;
}
往Vector尾部添加元素,与之类似的方法是add(E e)
方法,但是add
方法有返回值(返回true)。
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);
//将a中的元素全部拷贝到elementData中
System.arraycopy(a, 0, elementData, elementCount, numNew);
//更新elementCount
elementCount += numNew;
//如果numNew为0则返回false
return numNew != 0;
}
Vector为我们提供了两种迭代器,分别为ListItr和Itr。使用ListItr迭代器我们可以完成遍历,添加和修改节点的操作,使用ListItr我们不仅可以正向遍历链表也可以反向遍历。
使用Itr我们只能正向遍历,并且只提供删除操作,无法添加和修改节点。
文章同步【个人站】