什么是 Vector ?它的作用是什么?它的底层由什么组成?是否是线程安全的?
老样子,跟着上面的问题,我们层层深入了解 Vector 吧。
Vetcor 与 ArrayList 相似,其内部都是通过一个容量能够动态增长的 数组 来实现的。不同点是 Vector 是线程安全的。因为其内部有很多同步代码快来保证线程安全.
JDK 中原文有一句注释:
Vector is synchronized. If a thread-safe implementation is not needed, it is recommended to use ArrayList in place of Vector
表示如果不使用线程安全则可以使用 ArrayList ,因其效率比 Vector 高出不少。但是 Vector 是线程安全的,所以使用是比较好的。
一般使用 Vector :
Vector vector = new Vector<>();
继承图:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CwRl9nM6-1670855079344)(/Users/tiejiaxiaobao/Library/Application Support/typora-user-images/image-20221210175748310.png)]](https://img.pic99.top/dingtaihe/202404/4e44c928b41a9b0.png)
通过源码来看:
public class Vectorextends AbstractListimplements List, RandomAccess, Cloneable, java.io.Serializable
{....
}
从上述源码中我们能发现 Vector 实现了 RandomAccess、Cloneable和Serialzable 等接口。
Vector 继承了 List 类则可以使 Vector 能进行增删改查。底层则是使用 数组 : protected Object[] elementData;
和 ArrayList 一样,实现 RandomAccess 接口可以增加随机遍历的效率,能大大提高访问 Vector 数组的时间。
具体可参考本篇文章: 地址
为什么要实现 Serializable 接口呢?首先我们需要知道Java为什么需要序列化和反序列化。搞清楚这两个我们才能去理解为什么 Vector 要去实现 Serializable 这个接口。
之前在写 LinkedList 源码中曾写过具体的介绍,大家详情可以参考本篇文章嗷:地址 。
同 ArrayList 一样,实现了 Cloneable 接口,即 Vector 也可以实现浅拷贝和深度拷贝。
具体例子本篇就不过对赘述,详情可以参考本篇文章:地址 。
/*** The array buffer into which the components of the vector are* stored. The capacity of the vector is the length of this array buffer,* and is at least large enough to contain all the vector's elements.** Any array elements following the last element in the Vector are null.** @serial*/protected Object[] elementData;/*** The number of valid components in this {@code Vector} object.* Components {@code elementData[0]} through* {@code elementData[elementCount-1]} are the actual items.** @serial*/protected int elementCount;/*** The amount by which the capacity of the vector is automatically* incremented when its size becomes greater than its capacity. If* the capacity increment is less than or equal to zero, the capacity* of the vector is doubled each time it needs to grow.** @serial*/protected int capacityIncrement;/** use serialVersionUID from JDK 1.0.2 for interoperability */private static final long serialVersionUID = -2767605614048989439L;
elementData : 存储元素的数组,初始容量为10 。elementCount : 记录数组中元素个数 。capacityIncrement : 自动扩容的大小,即当数组满了之后,就添加capacityIncrement个空间装载元素,如果 capacityIncrement<=0,则扩容时就扩容到目前Vector容量的两倍 。serialVersionUID :该类的序列化版本号 。Vector 一共有四个构造函数:
3.2.1 Vector(int initialCapacity, int capacityIncrement):
指定容量和增长系数构造函数
源码:
/*** Constructs an empty vector with the specified initial capacity and* capacity increment.** @param initialCapacity the initial capacity of the vector* @param capacityIncrement the amount by which the capacity is* increased when the vector overflows* @throws IllegalArgumentException if the specified initial capacity* is negative*/public Vector(int initialCapacity, int capacityIncrement) {super();if (initialCapacity < 0)throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);this.elementData = new Object[initialCapacity];this.capacityIncrement = capacityIncrement;}
过程:
initialCapacity(指定容量的值) 是否小于0。如果小于零就抛出 IllegalArgumentException 异常。elementData 。capacityIncrement 。3.2.2 Vector(int initialCapacity)
指定容量
源码:
/*** Constructs an empty vector with the specified initial capacity and* with its capacity increment equal to zero.** @param initialCapacity the initial capacity of the vector* @throws IllegalArgumentException if the specified initial capacity* is negative*/public Vector(int initialCapacity) {this(initialCapacity, 0);}
指定初始化容量,增长系数默认为0。
3.2.3 Vector()
源码:
/*** Constructs an empty vector so that its internal data array* has size {@code 10} and its standard capacity increment is* zero.*/public Vector() {this(10);}
什么都不指定,默认给的容量是10。
3.2.4 Vector(Collection extends E> c)
指定集合初始化
源码:
/*** Constructs a vector containing the elements of the specified* collection, in the order they are returned by the collection's* iterator.** @param c the collection whose elements are to be placed into this* vector* @throws NullPointerException if the specified collection is null* @since 1.2*/public Vector(Collection extends E> c) {Object[] a = c.toArray();elementCount = a.length;if (c.getClass() == ArrayList.class) {elementData = a;} else {elementData = Arrays.copyOf(a, elementCount, Object[].class);}}
过程:
c 转化为 数组 a 。elementCount 。ArrayList ,则直接复制 。3.3.1 add(E e):
源码:
/*** Appends the specified element to the end of this Vector.** @param e element to be appended to this Vector* @return {@code true} (as specified by {@link Collection#add})* @since 1.2*/public synchronized boolean add(E e) {modCount++;ensureCapacityHelper(elementCount + 1);elementData[elementCount++] = e;return true;}/*** This implements the unsynchronized semantics of ensureCapacity.* Synchronized methods in this class can internally call this* method for ensuring capacity without incurring the cost of an* extra synchronization.** @see #ensureCapacity(int)*/private void ensureCapacityHelper(int minCapacity) {// overflow-conscious codeif (minCapacity - elementData.length > 0)grow(minCapacity);}
过程:
modCount 增加次数。grow() 方法的作用)。grow():
源码:
/*** The maximum size of array to allocate.* Some VMs reserve some header words in an array.* Attempts to allocate larger arrays may result in* OutOfMemoryError: Requested array size exceeds VM limit*/private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;private void grow(int minCapacity) {// overflow-conscious code// 以前的容量int oldCapacity = elementData.length;// 现在的容量,是以前的容量加上扩展系数,如果扩展系数小于等于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) // overflowthrow new OutOfMemoryError();return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;}
过程:
minCapacity 小于 minCapacity 。则就按照最小容量来扩容。OutOfMemoryError 异常。3.3.2 add(int index, E element)
源码:
/*** Inserts the specified element at the specified position in this Vector.* Shifts the element currently at that position (if any) and any* subsequent elements to the right (adds one to their indices).** @param index index at which the specified element is to be inserted* @param element element to be inserted* @throws ArrayIndexOutOfBoundsException if the index is out of range* ({@code index < 0 || index > size()})* @since 1.2*/public void add(int index, E element) {insertElementAt(element, index);}/*** Inserts the specified object as a component in this vector at the* specified {@code index}. Each component in this vector with* an index greater or equal to the specified {@code index} is* shifted upward to have an index one greater than the value it had* previously.** The index must be a value greater than or equal to {@code 0}* and less than or equal to the current size of the vector. (If the* index is equal to the current size of the vector, the new element* is appended to the Vector.)**
This method is identical in functionality to the* {@link #add(int, Object) add(int, E)}* method (which is part of the {@link List} interface). Note that the* {@code add} method reverses the order of the parameters, to more closely* match array usage.** @param obj the component to insert* @param index where to insert the new component* @throws ArrayIndexOutOfBoundsException if the index is out of range* ({@code index < 0 || index > size()})*/public synchronized void insertElementAt(E obj, int index) {// 修改次数增加modCount++;// 判断index是否非法if (index > elementCount) {throw new ArrayIndexOutOfBoundsException(index+ " > " + elementCount);}// 确保容量足够ensureCapacityHelper(elementCount + 1);// 拷贝数据,将后面的元素,往后移动一位System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);// 将实际的数据插入elementData[index] = obj;// 个数增加elementCount++;}
过程:
insertElementAt 。modCount 的修改次数。index 是否越界。Vector 中的容量是否够用。因为方法加了 synchronized 关键字可以保证线程安全,但是随之而来的就是效率的下降。
3.3.3 addAll(Collection extends E> c)
将一个集合所有元素添加进去
源码:
/*** Appends all of the elements in the specified Collection to the end of* this Vector, in the order that they are returned by the specified* Collection's Iterator. The behavior of this operation is undefined if* the specified Collection is modified while the operation is in progress.* (This implies that the behavior of this call is undefined if the* specified Collection is this Vector, and this Vector is nonempty.)** @param c elements to be inserted into this Vector* @return {@code true} if this Vector changed as a result of the call* @throws NullPointerException if the specified collection is null* @since 1.2*/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;}
过程:
modCount 。c 集合转化为数组并获取数组的长度。3.3.4 addAll(int index, Collection extends E> c)
指定index,插入一个集合,和前面不一样的地方在于复制之前,需要计算往后面移动多少位,不是用for循环去插入,而是一次性移动和写入。
源码:
/*** Inserts all of the elements in the specified Collection into this* Vector at the specified position. Shifts the element currently at* that position (if any) and any subsequent elements to the right* (increases their indices). The new elements will appear in the Vector* in the order that they are returned by the specified Collection's* iterator.** @param index index at which to insert the first element from the* specified collection* @param c elements to be inserted into this Vector* @return {@code true} if this Vector changed as a result of the call* @throws ArrayIndexOutOfBoundsException if the index is out of range* ({@code index < 0 || index > size()})* @throws NullPointerException if the specified collection is null* @since 1.2*/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;// 插入元素个数是否为0return numNew != 0;}
3.3.5 remove(Object o)
删除指定元素
源码:
/*** Removes the first occurrence of the specified element in this Vector* If the Vector does not contain the element, it is unchanged. More* formally, removes the element with the lowest index i such that* {@code (o==null ? get(i)==null : o.equals(get(i)))} (if such* an element exists).** @param o element to be removed from this Vector, if present* @return true if the Vector contained the specified element* @since 1.2*/// 实际调用的是removeElement()public boolean remove(Object o) {return removeElement(o);}// 线程安全public synchronized boolean removeElement(Object obj) {// 修改次数增加modCount++;// 获取第一个满足条件的元素缩影int i = indexOf(obj);// 如果索引满足条件if (i >= 0) {// 将索引为i的元素从数组中移除removeElementAt(i);// 返回删除成功的结果return true;}// 返回失败的结果return false;}// 线程安全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) {// 往前面移动一位(复制,覆盖)System.arraycopy(elementData, index + 1, elementData, index, j);}// 长度减1elementCount--;// 将最后一个元素指向null,最后GC会进行回收elementData[elementCount] = null; /* to let gc do its work */}
过程:
3.3.6 remove(int index)
按照索引删除元素
源码:
public synchronized E remove(int index) {// 修改次数增加modCount++;// 合法性判断if (index >= elementCount)throw new ArrayIndexOutOfBoundsException(index);// 保存原来的数据E oldValue = elementData(index);// 移动的个数int numMoved = elementCount - index - 1;// 如果移动个数大于0if (numMoved > 0)// 后面的元素往前面移动一位,赋值,覆盖System.arraycopy(elementData, index+1, elementData, index,numMoved);// 最后一个元素置空elementData[--elementCount] = null; // Let gc do its work// 返回旧的元素return oldValue;}
过程:
3.3.7 set
下面两个set函数都是,修改索引为index的元素,区别就是一个会返回旧的元素,一个不会返回旧的元素。
public synchronized E set(int index, E element) {// 合法性判断if (index >= elementCount)throw new ArrayIndexOutOfBoundsException(index);// 取出旧的元素E oldValue = elementData(index);// 更新elementData[index] = element;// 返回旧的元素return oldValue;}public synchronized void setElementAt(E obj, int index) {// 合法哦性判断if (index >= elementCount) {throw new ArrayIndexOutOfBoundsException(index + " >= " +elementCount);}// 直接更新elementData[index] = obj;}
3.3.8 get
源码:
public synchronized E get(int index) {// 合法判断if (index >= elementCount)throw new ArrayIndexOutOfBoundsException(index);// 返回数组的元素return elementData(index);}// 获取第一个元素:public synchronized E firstElement() {if (elementCount == 0) {throw new NoSuchElementException();}return elementData(0);}// 获取最后一个元素:public synchronized E lastElement() {if (elementCount == 0) {throw new NoSuchElementException();}return elementData(elementCount - 1);}E elementData(int index) {return (E) elementData[index];}
4.1 为什么要成倍的扩容而不是一次增加一个固定大小的容量呢?
4.2 为什么是以两倍的方式扩容而不是三倍四倍,或者其他方式呢?
4.3 Vector 和 ArrayList 的区别又有什么呢?
答案参考:地址