1.Vector介绍
Vector
和前面说的 ArrayList
很是类似,这里说的也是1.8版本,它是一个队列,但是本质上底层也是数组实现的。同样继承 AbstractList
,实现了 List
, RandomAcess
, Cloneable
, java.io.Serializable
接口。具有以下特点:
- 提供随机访问的功能:实现
RandomAcess
接口,这个接口主要是为List
提供快速访问的功能,也就是通过元素的索引,可以快速访问到。 - 可克隆:实现了
Cloneable
接口 - 是一个支持新增,删除,修改,查询,遍历等功能。
- 可序列化和反序列化
- 容量不够,可以触发自动扩容
- 最大的特点是:线程安全的 ,相当于线程安全的
ArrayList
。
定义源码如下:
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ }
2. 成员变量
底层是数组,增加元素,数组空间不够的时候,需要扩容。
- elementData:真正保存数据的数组
- elementCount:实际元素个数
- capacityIncrement:容量增加系数,就是扩容的时候增加的容量
- serialVersionUID:序列化id
// 真正保存数据的数组 protected Object[] elementData; // 元素个数 protected int elementCount; //容量增加系数 protected int capacityIncrement; // 序列化id private static final long serialVersionUID = -2767605614048989439L;
3. 构造函数
Vector
一共有四个构造函数:
- 指定容量和增长系数
- 指定容量
- 不指定,使用默认容量值10
- 指定集合初始化
1.指定容量和增长系数构造函数
public Vector(int initialCapacity, int capacityIncrement) { super(); // 非法判断 if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); // 初始化数组 this.elementData = new Object[initialCapacity]; // 指定增长系数 this.capacityIncrement = capacityIncrement; }
2.指定初始化容量,增长系数默认为0
public Vector(int initialCapacity) { this(initialCapacity, 0); }
3.什么都不指定,默认给的容量是10:
public Vector() { this(10); }
4.指定集合初始化:
public Vector(Collection<? extends E> c) { // 转换成为数组 Object[] a = c.toArray(); // 大小为数组的大小 elementCount = a.length; // 如果是ArrayList,则直接复制 if (c.getClass() == ArrayList.class) { elementData = a; } else { // 否则需要进行拷贝 elementData = Arrays.copyOf(a, elementCount, Object[].class); } }
4. 常用方法
4.1 增加
增加元素,默认是在最后添加,如果容量不够的时候会触发扩容机制。
public synchronized void addElement(E obj) { // 修改次数增加 modCount++; // 确保容量足够(如果需要,里面会有扩容,复制操作) ensureCapacityHelper(elementCount + 1); // 将新元素放在最后一个元素,个数增加 elementData[elementCount++] = obj; }
那么它是如何确保容量的呢?
可以看到 ensureCapacityHelper()
里面判断增加后的元素个数是否大于现在数组的长度,如果不满足,就需要扩容。调用 grow()
函数扩容。
private void ensureCapacityHelper(int minCapacity) { // overflow-conscious code if (minCapacity - elementData.length > 0) grow(minCapacity); } // 扩容,传入的是需要最小的容量 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); }
在指定的索引index,插入数据,实际上调用的是 insertElementAt(element, index)
.
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++; }
将一个集合所有元素添加进去:
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; }
指定index,插入一个集合,和前面不一样的地方在于复制之前,需要计算往后面移动多少位,不是用for循环去插入,而是一次性移动和写入。
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; // 插入元素个数是否为0 return numNew != 0; }
4.2 删除
删除指定元素
public boolean remove(Object o) { return removeElement(o); } // 实际调用的是removeElement() public synchronized boolean removeElement(Object obj) { // 修改次数增加 modCount++; // 获取第一个满足条件的元素缩影 int i = indexOf(obj); // 索引如果满足条件 if (i >= 0) { // 将索引为i的元素从数组中移除 removeElementAt(i); return true; } return false; } // 操作数组删除元素