Vector
Vector
类实现了一个可增长的对象数组。像数组一样,它包含可以使用整数索引访问的组件。但是,Vector
的大小可以根据需要增加或缩小,以在Vector
创建后能够添加和删除项目。
每个vector都尝试通过维护一个capacity
和一个capacityIncrement
来优化存储管理。capacity
始终至少与vector大小一样大,通常它会更大,因为随着组件添加到vector中,vector的存储以块的形式增加capacityIncrement
的大小。一个应用程序可以在插入大量组件之前增加一个vector的容量,这将减少增量重新分配的次数。
此类的iterator
和listIterator
方法返回的迭代器是“快速失败”的:如果在创建迭代器后的任何时间对vector进行结构上的修改,除了通过迭代器自己的remove
或add
方法之外,迭代器将抛出一个ConcurrentModificationException
。因此,面对并发修改,迭代器快速而干净地失败,而不是在未来不确定的时间冒任意、不确定行为的风险。elements
方法返回的Enumeration
不是快速失败的。
请注意,无法保证迭代器的快速失败行为,因为一般而言,在存在非同步地并发修改的情况下不可能做出任何严格保证。快速失败的迭代器会尽最大努力抛出ConcurrentModificationException
。因此,编写一个依赖于这个异常来保证其正确性的程序是错误的:迭代器的快速失败行为应该只用于检测错误。
从 Java 2 平台 v1.2 开始,该类经过改造实现了List
接口,使其成为“Java 集合框架”的成员。与新的集合实现不同,Vector
是同步的。如果不需要线程安全的实现,建议使用ArrayList
代替Vector
。
存储vector组件的数组缓冲区。vector的容量是这个数组缓冲区的长度,并且至少足够包含vector的所有元素。
Vector
中最后一个元素之后的任何数组元素都为空。
此Vector
对象中的有效组件数。组件elementData[0]
到elementData[elementCount-1]
是实际的条目。
当vector的大小要变得大于其容量时,vector的容量自动增加的量。如果容量增量小于或等于零,则每次需要增长时,vector的容量都会增加一倍。
使用 JDK 1.0.2 中的 serialVersionUID
实现互通性。
构造一个具有指定初始容量和容量增量的空vector。
其源码如下:
public Vector(int initialCapacity, int capacityIncrement) {
// 调用AbstractList()
super();
// 初始容量不可小于0
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
// 初始化组件数组,也即元素数组
this.elementData = new Object[initialCapacity];
// 设定容量增量
this.capacityIncrement = capacityIncrement;
}
构造一个具有指定初始容量且容量增量为零的空vector。
源码如下:
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
构造一个空vector,使其内部数据数组的大小为10
并且其标准容量增量为零。
源码如下:
public Vector() {
this(10);
}
构造一个包含指定集合元素的vector,按照集合的迭代器返回的顺序。
源码如下:
public Vector(Collection<? extends E> c) {
// 将参数中给定集合转化为数组
Object[] a = c.toArray();
// 数组长度即本Vector实例的元素数量
elementCount = a.length;
// 如果指定集合是ArrayList,则数组a可直接赋值给本Vector实例用于存储数据的数组
if (c.getClass() == ArrayList.class) {
elementData = a;
} else {
// 非ArrayList,可能与Vector实现差异较大,此处进行数组复制
elementData = Arrays.copyOf(a, elementCount, Object[].class);
}
}
将此vector的组件(即元素)复制到指定的数组中。此vector中索引k
处的项目被复制到anArray
的k
位置。
源码如下:
public synchronized void copyInto(Object[] anArray) {
System.arraycopy(elementData, 0, anArray, 0, elementCount);
}
将此vector的容量修剪为vector的当前大小。如果此vector的容量大于其当前大小,则通过将其内部数据数组替换为较小的数组,将容量更改为等于大小,该数组保存在字段elementData
中。应用程序可以使用此操作来最小化vector的存储。
public synchronized void trimToSize() {
// 增加修改次数
modCount++;
// 取出当前数组长度
int oldCapacity = elementData.length;
// 如果当前元素个数 小于 当前数组长度
if (elementCount < oldCapacity) {
// 复制当前数组存放了数据的部分,也即丢弃数组后面未存放元素的部分
elementData = Arrays.copyOf(elementData, elementCount);
}
}
如有必要,增加此vector的容量,以确保它至少可以容纳由最小容量参数指定的组件数量。
如果此vector的当前容量小于minCapacity
,则通过将其保存在字段elementData
中的内部数据数组替换为更大的数组来增加其容量。新数据数组的大小为旧大小加上capacityIncrement
,除非capacityIncrement
的值小于或等于0,在这种情况下,新容量将是旧容量的两倍;但如果这个新大小仍然小于minCapacity
,那么新容量将是minCapacity
。
源码如下:
public synchronized void ensureCapacity(int minCapacity) {
if (minCapacity > 0) {
// 增加修改次数
modCount++;
// 调用确保容量方法的非同步版本
ensureCapacityHelper(minCapacity);
}
}
本方法实现了ensureCapacity
的非同步版本。本类中的同步方法可以在内部调用此方法以确保容量,而不会产生额外同步的成本。
源码如下:
private void ensureCapacityHelper(int minCapacity) {
// overflow-conscious code
// 如果参数中的最小容量大于当前vector存放数据的数组容量,则调用grow方法增大数组的容量
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
要分配的数组的最大大小。
一些 VM 在数组中保留一些头字。
尝试分配更大的数组可能会导致OutOfMemoryError
:请求的数组大小超出 VM 限制
增加数组elementData
大小。
源码如下:
private void grow(int minCapacity) {
// overflow-conscious code
// 取出当前数组elementData的容量
int oldCapacity = elementData.length;
// 如果容量增量大于0,则 新数组容量 = 旧数组容量 + 容量增量
// 否则, 新数组容量 = 旧数组容量 + 旧数组容量
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
// 经上述逻辑计算出的新数组容量如果仍小于参数中指定的最小容量,则新数组容量直接取参数中的最小容量
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 经上述逻辑计算出的新数组容量如果大于Vector限定的数组最大数量,则调用获取最大容量方法
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 将elementData复制到扩容后的新数组
elementData = Arrays.copyOf(elementData, newCapacity);
}
获取巨大的容量。
源码如下:
private static int hugeCapacity(int minCapacity) {
// 如果最小容量小于0,则抛出OutOfMemoryError
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
// 如果最小容量大于Vector设定的最大数组容量,则巨大容量取Integer的最大值
// 否则,巨大容量取Vector设定的最大数组容量
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
设置此vector的大小。如果新大小大于当前大小,则往此vector的末尾添加null
。如果新大小小于当前大小,则索引newSize
位置及其之后的所有组件都将被丢弃。
源码如下:
public synchronized void setSize(int newSize) {
// 增加修改次数
modCount++;
// 如果新大小大于当前元素个数,则调用ensureCapacityHelper确保数组容量
if (newSize > elementCount) {
ensureCapacityHelper(newSize);
} else {
// 新大小小于等于当前元素个数,则遍历数组从新大小到元素个数-1位置的部分
// 将遍历到的每个元素都置为null
for (int i = newSize ; i < elementCount ; i++) {
elementData[i] = null;
}
}
// 将元素个数置为新大小
elementCount = newSize;
}
返回此vector的当前容量。
当前容量:其内部数据数组(即此vector的elementData
字段)的长度。
源码如下:
public synchronized int capacity() {
return elementData.length;
}
返回此vector中的组件数(即元素个数)。
源码如下:
public synchronized int size() {
return elementCount;
}
测试此vector是否没有组件。
源码如下:
public synchronized boolean isEmpty() {
return elementCount == 0;
}
返回此vector的组件的枚举。返回的Enumeration
对象将生成此向量中的所有项目。生成的第一项是索引0
处的项,然后是索引1
处的项,依此类推。
源码如下:
public Enumeration<E> elements() {
// 因为Enumeration是一个接口,所以此处返回的是一个它的匿名内部类
// 该接口有两个方法:hasMoreElements()、nextElement()
return new Enumeration<E>() {
// 从0开始计数,此处count可以理解为游标
int count = 0;
// 判断是否还有其他元素
public boolean hasMoreElements() {
// 判断当前游标是否小于元素个数
return count < elementCount;
}
// 获取下一个元素
public E nextElement() {
synchronized (Vector.this) {
if (count < elementCount) {
// 如果当前游标小于当前元素个数,则返回当前游标位置的元素
return elementData(count++);
}
}
throw new NoSuchElementException("Vector Enumeration");
}
};
}
如果此vector包含指定的元素,则返回true
。更正式地说,当且仅当此vector包含至少一个元素e
使得(o==null ? e==null : o.equals(e))
时才返回true
。
源码如下:
public boolean contains(Object o) {
// 调用indexOf方法判断指定元素在数组中的索引位置是否大于等于0
return indexOf(o, 0) >= 0;
}
返回指定元素在此vector中第一次出现的索引,如果此向量不包含该元素,则返回-1
。更正式地说,返回最小索引i
使得(o==null ? get(i)==null : o.equals(get(i)))
,或者如果有是没有这样的索引则返回-1
。
源码如下:
public int indexOf(Object o) {
// 从索引位置0处开始匹配
return indexOf(o, 0);
}
返回此vector中指定元素第一次出现的索引,从index
开始搜索,如果未找到该元素,则返回-1
。更正式地说,返回最小索引i
使得(i >= index && (o==null ? get(i)==null : o.equals(get(i))))
,如果没有这样的索引,则返回-1
。
源码如下:
public synchronized int indexOf(Object o, int index) {
if (o == null) {
// 指定对象为null,则遍历数组找到元素为null的索引位置
for (int i = index ; i < elementCount ; i++)
if (elementData[i]==null)
return i;
} else {
// 指定对象不为null,则遍历数组找到equals为true的元素的索引位置
for (int i = index ; i < elementCount ; i++)
if (o.equals(elementData[i]))
return i;
}
// 找不到则返回-1
return -1;
}
返回指定元素在此vector中最后一次出现的索引,如果此vector不包含该元素,则返回-1
。更正式地,返回最大索引i
使得(o==null ? get(i)==null : o.equals(get(i)))
,或者如果没有这样的索引则返回-1
。
源码如下:
public synchronized int lastIndexOf(Object o) {
return lastIndexOf(o, elementCount-1);
}
返回指定元素在此vector中最后一次出现的索引,从index
开始向前搜索(即向索引变小的方向搜索),如果未找到该元素,则返回-1
。更正式地说,返回最高索引i
使得(i <= index && (o==null ? get(i)==null : o.equals(get(i))))
,如果没有这样的索引则返回-1
。
源码如下:
public synchronized int lastIndexOf(Object o, int index) {
// 检查开始索引是否大于等于元素个数,如果是则抛出数组越界异常
if (index >= elementCount)
throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
// 和indexOf方法类似,指定对象是否为空走不同的逻辑
if (o == null) {
// 从index位置开始,一直往前遍历(索引变小的方向)
for (int i = index; i >= 0; i--)
// 命中即返回
if (elementData[i]==null)
return i;
} else {
for (int i = index; i >= 0; i--)
if (o.equals(elementData[i]))
return i;
}
// 未找到,则返回-1
return -1;
}
返回指定索引处的组件(即元素)。
此方法在功能上与get(int)
方法相同(get(int)
是List
接口的方法之一)。
源码如下:
public synchronized E elementAt(int index) {
// 数组越界检查
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
}
// 调用elementData方法
return elementData(index);
}
返回此vector的第一个组件(索引0
处的项目)。
源码如下:
public synchronized E firstElement() {
if (elementCount == 0) {
throw new NoSuchElementException();
}
// 没有特殊逻辑,就是从数组中根据索引0取数据
return elementData(0);
}
返回vector的最后一个组件。
源码如下:
public synchronized E lastElement() {
if (elementCount == 0) {
throw new NoSuchElementException();
}
// 返回elementData数组中最后一个元素,对应索引位置为:元素个数 - 1
return elementData(elementCount - 1);
}
将此vector的指定index
处的组件设置为指定对象,该位置之前的组件将被丢弃。
该索引必须大于或等于0
且小于vector的当前大小。
此方法在功能上与set(int, E)
方法(它是List
接口的方法之一)相同。请注意,set
方法颠倒了参数的顺序,以更紧密地匹配数组用法。另请注意,set
方法会返回存储在指定位置的旧值。
源码如下:
public synchronized void setElementAt(E obj, int index) {
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
elementData[index] = obj;
}
删除指定索引处的组件。此vector中索引大于或等于指定index
的每个组件向前移动,使其索引比之前的值小 1。这个vector的大小减少1
。
索引必须是大于或等于0
且小于vector的当前大小的值。
此方法在功能上与remove(int)
方法(它是List
接口的一部分)相同。需要注意,remove
方法会返回存储在指定位置的旧值。
源码如下:
public synchronized void removeElementAt(int index) {
// 增加修改次数
modCount++;
// 校验指定的索引index是否出于合理区间(即:大于等于0且小于元素个数)
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
// 计算出所需要异动位置的元素个数
int j = elementCount - index - 1;
if (j > 0) {
// 进行数组复制
// 将elementData数组的“index+1”及之后的元素复制到elementData数组的“index”处及之后的位置
// 复制元素的个数为j
System.arraycopy(elementData, index + 1, elementData, index, j);
}
// 元素个数减一
elementCount--;
// 将末尾的元素置为null,以使其可被垃圾回收
elementData[elementCount] = null; /* to let gc do its work */
}
将指定对象作为组件插入此vector中指定index
处。此vector中索引大于或等于指定index
的每个组件向后移动,使其索引比之前的值大 1。
索引必须是大于等于0
且小于等于vector的当前大小的值。(如果索引等于vector的当前大小,则新元素将追加到当前vector。)
此方法在功能上与add(int, E)
方法(它是List
接口的一部分)相同。需要注意,add
方法颠倒了参数的顺序,以更接近数组用法。
源码如下:
public synchronized void insertElementAt(E obj, int index) {
// 修改次数加1
modCount++;
// 校验指定的索引index是否在合理的区间内
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
// 确保vector容量足够
ensureCapacityHelper(elementCount + 1);
// 执行数组复制,将elementData数组index及之后的元素复制到elementData的index+1处及之后的位置
// 复制的元素个数为元素个数-指定索引index
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
// 此时给index位置替换元素为指定的元素obj
elementData[index] = obj;
// 元素个数加1
elementCount++;
}
将指定的组件添加到此vector的末尾,将其大小增加 1。如果该vector的大小变得大于其容量,则该vector的容量会增加。
此方法在功能上与add(E)
方法(它是List
接口的一部分)相同。
源码如下:
public synchronized void addElement(E obj) {
// 修改次数加1
modCount++;
// 确保容量足够(不够的话会进行扩容)
ensureCapacityHelper(elementCount + 1);
// 将指定元素拼接到vector的末尾
elementData[elementCount++] = obj;
}
从此vector中删除指定参数的第一次(最低索引)出现。如果在此vector中找到对象,则向量中索引大于或等于该指定对象索引的每个元素将向前移动,使其索引比之前的值减1。
此方法在功能上与remove(Object)
方法(它是List
接口的一部分)相同。
源码如下:
public synchronized boolean removeElement(Object obj) {
// 修改次数加1
modCount++;
// 找到指定元素的索引位置(最小的那个)
int i = indexOf(obj);
// 如果找到了,则删除并返回true,否则返回false
if (i >= 0) {
// 删除指定索引位置的元素
removeElementAt(i);
return true;
}
return false;
}
删除此vector中的所有组件并将其大小设置为零。
此方法在功能上与clear
方法(它是List
接口的一部分)相同。
源码如下:
public synchronized void removeAllElements() {
// 修改次数加1
modCount++;
// Let gc do its work
// 遍历数组,将所有元素置为null,以使其可被垃圾回收
for (int i = 0; i < elementCount; i++)
elementData[i] = null;
// 将元素个数置为0
elementCount = 0;
}
返回此vector的克隆。该副本将包含对内部数据数组副本的引用,而不是对这个Vector
对象的原始内部数据数组的引用。
源码如下:
public synchronized Object clone() {
try {
// 调用Object的clone方法获取一个Vector对象,但此时持有元素的数据数组未被复制
@SuppressWarnings("unchecked")
Vector<E> v = (Vector<E>) super.clone();
// 将持有元素的数据数组复制一份,并赋值给上面新得到的Vector对象
v.elementData = Arrays.copyOf(elementData, elementCount);
// 修改次数赋值为0
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}
以正确的顺序返回包含此Vector
中所有元素的数组。
源码如下:
public synchronized Object[] toArray() {
// 返回的是内部数据数组的副本
return Arrays.copyOf(elementData, elementCount);
}
以正确的顺序返回包含此Vector
中所有元素的数组;返回数组的运行时类型是指定数组的类型。如果Vector
适合指定的数组,则在其中返回。否则,将使用指定数组的运行时类型和此Vector
的大小分配一个新数组。
如果Vector
适合指定的数组并有剩余空间(即,该数组的元素比Vector
多),则紧跟Vector
末尾的数组中的元素将设置为null
。(如果调用者知道Vector
不包含任何空元素,这对于确定Vector
的长度很有用。)
源码如下:
@SuppressWarnings("unchecked")
public synchronized <T> T[] toArray(T[] a) {
// 如果指定的数组a的大小小于当前Vector对象的元素个数,则直接数组复制到一个新的数组并返回
if (a.length < elementCount)
return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
// 指定数组a的大小大于等于当前Vector对象的元素个数,说明其可以承载当前Vector的所有元素
// 将Vector对象中持有元素的数据数组复制到指定的数组a
System.arraycopy(elementData, 0, a, 0, elementCount);
// 如果指定的数组a的容量大于当前Vector对象的大小,则在数组a的最后一个元素的下一个元素设置为null(也即elementCount索引位置)
if (a.length > elementCount)
a[elementCount] = null;
return a;
}
获取指定索引位置的元素。
源码如下:
@SuppressWarnings("unchecked")
E elementData(int index) {
// 直接从数组中取出指定索引位置的元素
return (E) elementData[index];
}
返回此Vector
中指定位置的元素。
public synchronized E get(int index) {
// 指定索引的合法性检查
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
// 返回数组中指定位置的元素
return elementData(index);
}
用指定的元素替换此Vector
中指定位置的元素。
源码如下:
public synchronized E set(int index, E element) {
// 指定索引的合法性检查
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
// 取出指定索引位置的原值
E oldValue = elementData(index);
// 将指定索引位置的元素替换为指定的元素
elementData[index] = element;
// 返回此索引位置的原值
return oldValue;
}
将指定的元素附加到此Vector
的末尾。
源码如下:
public synchronized boolean add(E e) {
// 修改次数加1
modCount++;
// 确保容量足够
ensureCapacityHelper(elementCount + 1);
// 将数组的elementCount索引位置设置为指定元素e,然后将elementCount加1
elementData[elementCount++] = e;
return true;
}
移除此Vector
中第一次出现的指定元素,如果Vector
不包含该元素,则它保持不变。更正式地说,删除满足(o==null ? get(i)==null : o.equals(get(i)))
的最低索引i
的元素,(如果存在这样的元素)。
源码如下:
public boolean remove(Object o) {
return removeElement(o);
}
在此Vector
的指定位置插入指定元素。将当前在该位置的元素(如果有)和任何后续元素向右移动(将它们的索引加一)。
源码如下:
public void add(int index, E element) {
insertElementAt(element, index);
}
移除此Vector
中指定位置的元素。将任何后续元素向左移动(将它们的索引中减一)。返回从Vector
中删除的元素。
源码如下:
public synchronized E remove(int index) {
// 修改次数加1
modCount++;
// 指定索引的合法性校验
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
// 取出指定索引位置的原值
E oldValue = elementData(index);
// 需要移动索引位置的元素个数 = 指定索引及其后面的元素
int numMoved = elementCount - index - 1;
// 需要移动索引的元素个数大于0,则通过数组复制进行批量移动
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 将元素个数减1,然后将元素个数位置的元素置为null,以使其可被垃圾回收
elementData[--elementCount] = null; // Let gc do its work
// 返回原值
return oldValue;
}
从此Vector
中删除所有元素。此调用返回后,Vector
将为空(除非它引发异常)。
源码如下:
public void clear() {
removeAllElements();
}
如果此Vector
包含指定Collection
中的所有元素,则返回true
。
当指定的集合为空时,会抛出NullPointerException
。
源码如下:
public synchronized boolean containsAll(Collection<?> c) {
// 调用AbstractCollection的containsAll进行判断
return super.containsAll(c);
}
将指定Collection
中的所有元素按照指定该集合的迭代器返回的顺序追加到此Vector
的末尾。如果在操作进行时修改了指定的Collection
,则此操作的行为将变得未知。 (这意味着如果指定的Collection
是此Vector
且此Vector
非空,则此次调用的行为未知。)
如果此Vector
由于调用而更改,则返回true
。
源码如下:
public synchronized boolean addAll(Collection<? extends E> c) {
// 修改次数加1
modCount++;
// 将指定的集合转化为数组
Object[] a = c.toArray();
// 取出数组的长度
int numNew = a.length;
// 确保容量足够容纳下此数组
ensureCapacityHelper(elementCount + numNew);
// 将数组a复制到此Vector的最后一个元素后面
System.arraycopy(a, 0, elementData, elementCount, numNew);
// 增加元素个数
elementCount += numNew;
// 返回新增加的元素个数是否不为0,不为0说明有新元素添加到此Vector,返回true
return numNew != 0;
}
从此Vector
中删除包含在指定Collection
中的所有元素。
源码如下:
public synchronized boolean removeAll(Collection<?> c) {
// 调用AbstractCollection的removeAll方法
return super.removeAll(c);
}
仅保留此Vector
中包含在指定Collection
中的元素。换句话说,从此Vector
中删除所有未包含在指定Collection
中的元素。
源码如下:
public synchronized boolean retainAll(Collection<?> c) {
// 调用AbstractCollection的retainAll方法
return super.retainAll(c);
}
将指定Collection
中的所有元素插入此Vector
的指定位置。将当前在该位置的元素(如果有)和任何后续元素向右移动(增加它们的索引)。新元素将按照指定集合的迭代器返回的顺序出现在Vector
中。
public synchronized boolean addAll(int index, Collection<? extends E> c) {
// 增加修改次数
modCount++;
// 指定索引的合法性校验,大于等于0 且 小于等于元素个数
if (index < 0 || index > elementCount)
throw new ArrayIndexOutOfBoundsException(index);
// 将指定集合转化为数组
Object[] a = c.toArray();
// 数组大小
int numNew = a.length;
// 确保此Vector的容量足够容纳下指定集合的所有元素
ensureCapacityHelper(elementCount + numNew);
// 需移动索引的元素个数
int numMoved = elementCount - index;
// 如果需移动索引的元素个数大于0,则执行数组复制,先往后移动这些元素
if (numMoved > 0)
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
// 将指定集合转化的数组复制到此Vector数据数组的指定位置
System.arraycopy(a, 0, elementData, index, numNew);
// 元素个数增加
elementCount += numNew;
// 返回是否新增了元素至此Vector
return numNew != 0;
}
比较指定的Object
与此Vector
是否相等。当且仅当指定的Object
也是一个List
,两个List
的大小相同,并且两个List
中所有对应的元素对都相等时,才返回true
。(如果(e1==null ? e2==null : e1.equals(e2))
,说明两个元素e1
和e2
相等。)换句话说, 如果两个List
以相同的顺序包含相同的元素,则它们被定义为相等。
源码如下:
public synchronized boolean equals(Object o) {
// 调用AbstractList的equals方法
return super.equals(o);
}
返回此Vector
的哈希编码值。
源码如下:
public synchronized int hashCode() {
// 调用AbstractList的hashCode方法
return super.hashCode();
}
返回此Vector
的字符串表示形式,其中包含每个元素的字符串表示形式。
源码如下:
public synchronized String toString() {
// 调用AbstractCollection的toString方法
return super.toString();
}
返回此List
中的fromIndex
(包含)和toIndex
(不包含)之间部分的视图。 (如果fromIndex
和toIndex
相等,则返回的List
为空。)返回的List
基于此List
,因此返回的List
中的更改会反映在此List
中,反之亦然。返回的List
支持此List
支持的所有可选List
操作。
这种方法消除了对显式范围操作(数组通常存在的排序)的需要。通过对子列表视图而不是整个列表进行操作,任何需要列表的操作都可以用作范围操作。例如,以下惯用语法从List
中删除一系列元素:list.subList(from, to).clear();
,可以为indexOf
和lastIndexOf
构造类似的习惯用法,并且Collections
类中的所有算法都可以应用于子列表。
如果基础列表(即此列表)以除了通过返回列表以外的任何方式进行了结构修改,则此方法返回的列表的语义将变得未知。 (结构修改是那些改变List
的大小,或者以其他方式扰乱它,以致正在进行的迭代可能会产生不正确的结果。)
源码如下:
public synchronized List<E> subList(int fromIndex, int toIndex) {
// 调用Collections中的方法获取一个同步的列表
return Collections.synchronizedList(super.subList(fromIndex, toIndex),
this);
}
从此列表中删除所有索引在fromIndex
(含)和toIndex
(不含)之间的所有元素。将所有后续元素向左移动(减小其索引)。此调用减小列表的(toIndex-fromIndex
)个元素。 (如果toIndex == fromIndex
,则此操作无效。)
源码如下:
protected synchronized void removeRange(int fromIndex, int toIndex) {
// 增加修改次数
modCount++;
// 计算出需移动多少个元素
int numMoved = elementCount - toIndex;
// 将需移动的元素往前移动至fromIndex处
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);
// Let gc do its work
// 此时,Vector对象的元素个数未变,因为要被删除的范围内的元素已被其后的元素覆盖
// 需要将移动前的索引位置的元素置为空,以促使垃圾回收
// 例如:
// 原Vector:[0, 1, 2, 3, 4],现在对其调用removeRange(1, 3)方法
// 数组复制后:[0, 3, 4, 3, 4]
// 最终:[0, 3, 4]
int newElementCount = elementCount - (toIndex-fromIndex);
while (elementCount != newElementCount)
elementData[--elementCount] = null;
}
从流中加载Vector
实例(即反序列化它)。此方法执行检查以确保字段的一致性。
源码如下:
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
// 从流中读取出字段信息
ObjectInputStream.GetField gfields = in.readFields();
// 取出elementCount字段的值
int count = gfields.get("elementCount", 0);
// 取出elementData字段的值
Object[] data = (Object[])gfields.get("elementData", null);
// 对取出字段的合理性做校验
// 判断包括:count不能小于0 且 data不能为空 且count需与data的长度一致
if (count < 0 || data == null || count > data.length) {
throw new StreamCorruptedException("Inconsistent vector internals");
}
// 将流中的elementCount赋值给当前Vector的elementCount
elementCount = count;
// 将流中的elementData数组的拷贝赋值给当前Vector的elementData
elementData = data.clone();
}
将Vector
实例的状态保存到流中(即序列化它)。该方法执行同步以保证序列化数据的一致性。
源码如下:
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
final java.io.ObjectOutputStream.PutField fields = s.putFields();
final Object[] data;
synchronized (this) {
// 将capacityIncrement放入流
fields.put("capacityIncrement", capacityIncrement);
// 将elementCount放入流
fields.put("elementCount", elementCount);
// 执行对象数组的复制
data = elementData.clone();
}
// 将对象数组的拷贝放入流
fields.put("elementData", data);
// 将上述设定写入流中
s.writeFields();
}
返回在此列表元素上从指定位置开始的列表迭代器(以适当的顺序)。指定的索引指示初始调用next
将返回的第一个元素。初次调用previous
将返回指定索引减一的元素。
返回的列表迭代器是“快速失败”的。
源码如下:
public synchronized ListIterator<E> listIterator(int index) {
// 指定索引的合理性校验
if (index < 0 || index > elementCount)
throw new IndexOutOfBoundsException("Index: "+index);
// 返回一个ListItr实例
return new ListItr(index);
}
返回此列表中的元素的列表迭代器(按适当顺序)。
返回的列表迭代器是“快速失败”的。
源码如下:
public synchronized ListIterator<E> listIterator() {
// 返回一个从索引位置0处开始的列表迭代器实例
return new ListItr(0);
}
返回在此列表中元素上的迭代器(以正确的顺序)。
返回的迭代器是“快速失败”的。
源码如下:
public synchronized Iterator<E> iterator() {
// 返回一个Itr实例
return new Itr();
}
AbstractList.Itr
的优化版本。
要返回的下一个元素的索引,也即“游标“。
返回的最后一个元素的索引,如果还没有返回过元素,则是-1
。
期望更新次数,默认值取当前Vector
的修改次数。
判断是否还有下一个元素可返回,若有,则返回true
。
源码如下:
public boolean hasNext() {
// Racy but within spec, since modifications are checked
// within or after synchronization in next/previous
// 返回当前游标是否处于elementCount索引位置
return cursor != elementCount;
}
获取下一个元素。
源码如下:
public E next() {
synchronized (Vector.this) {
// 检查是否有修改
checkForComodification();
int i = cursor;
// 如果当前游标大于等于元素个数,则抛出无此元素异常
if (i >= elementCount)
throw new NoSuchElementException();
// 游标后移一位(即加1)
cursor = i + 1;
// 将移动前的原游标位置赋值给最后返回的索引字段,然后取出该位置的元素返回
return elementData(lastRet = i);
}
}
删除当前迭代器最近一次返回的元素。
源码如下:
public void remove() {
// 如果最后返回索引字段的值为-1,说明要么还未调用next获取过元素,要么已经删除过该元素
if (lastRet == -1)
throw new IllegalStateException();
synchronized (Vector.this) {
checkForComodification();
// 调用Vector的remove方法删除最后返回索引位置的元素
Vector.this.remove(lastRet);
// 更新期望更新次数
expectedModCount = modCount;
}
// 当前游标置于最近一次返回的索引处
cursor = lastRet;
// 最近返回的索引字段的值置为-1
lastRet = -1;
}
对迭代器尚未遍历到的元素执行给定的操作。
源码如下:
@Override
public void forEachRemaining(Consumer<? super E> action) {
Objects.requireNonNull(action);
synchronized (Vector.this) {
final int size = elementCount;
int i = cursor;
// 如果当前游标位置大于等于元素个数,在说明没有未遍历到的元素了,此时直接返回
if (i >= size) {
return;
}
// 啊,这个缩进看的真难受
@SuppressWarnings("unchecked")
// 取出当前Vector存放数据的数组
final E[] elementData = (E[]) Vector.this.elementData;
// 如果当前游标位置大于等于数组长度,说明可能存在并发修改,此时将抛出异常
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
// 遍历剩余的元素,每次都执行并发修改检查
while (i != size && modCount == expectedModCount) {
// 对遍历到的元素执行给定的操作
action.accept(elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
// 在遍历结束时更新一次以减少堆写入流量
cursor = i;
lastRet = i - 1;
// 再执行并发修改检查
checkForComodification();
}
}
检查是否存在并发修改。
源码如下:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
AbstractList.ListItr
的优化版本。
构建一个ListItr
。
源码如下:
ListItr(int index) {
super();
cursor = index;
}
判断前面是否还有元素可返回,若有,则返回true
。
源码如下:
public boolean hasPrevious() {
// 若当前游标不在索引位置0处,说明前面还有元素可返回
return cursor != 0;
}
返回下一个元素的索引。
源码如下:
public int nextIndex() {
// 即返回游标位置
return cursor;
}
返回上一个元素的索引。
源码如下:
public int previousIndex() {
// 返回当前游标位置减1
return cursor - 1;
}
返回上一个元素。
源码如下:
public E previous() {
synchronized (Vector.this) {
checkForComodification();
// 取出前面一个元素的索引位置
int i = cursor - 1;
// 如果得到的索引位置小于0,则说明前面没有元素了,此时抛出异常
if (i < 0)
throw new NoSuchElementException();
// 将得到的索引位置赋值给游标
cursor = i;
// 将得到的索引位置赋值给最近一次返回的元素索引字段,然后返回该位置的元素
return elementData(lastRet = i);
}
}
替换掉最近一次返回的元素。
源码如下:
public void set(E e) {
// 如果最近返回的元素索引位置为-1,说明此时没有最近一次返回的元素(也可能已被删除),则此时抛出异常
if (lastRet == -1)
throw new IllegalStateException();
synchronized (Vector.this) {
checkForComodification();
// 调用Vector的set方法 替换最近一次返回的元素为指定的元素
Vector.this.set(lastRet, e);
}
}
在最近一次返回的元素后面添加参数中指定的元素。
源码如下:
public void add(E e) {
int i = cursor;
synchronized (Vector.this) {
checkForComodification();
// 在当前游标位置插入指定的元素e
Vector.this.add(i, e);
// 更新期望更新次数
expectedModCount = modCount;
}
// 游标后移一位
cursor = i + 1;
// 最近返回的元素索引置为-1
lastRet = -1;
}
对当前Vector
实例的每个元素执行给定的动作。
源码如下:
@Override
public synchronized void forEach(Consumer<? super E> action) {
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[]) this.elementData;
final int elementCount = this.elementCount;
// 遍历当前Vector的对象数组
for (int i=0; modCount == expectedModCount && i < elementCount; i++) {
// 对每个元素执行给定动作
action.accept(elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
}
删除当前Vector实例中满足给定条件的元素。
源码如下:
@Override
@SuppressWarnings("unchecked")
public synchronized boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
// 先找出要被删除的元素
// figure out which elements are to be removed
// 判断过程中抛出了任何异常,都不会导致此集合改变
// any exception thrown from the filter predicate at this stage
// will leave the collection unmodified
int removeCount = 0;
final int size = elementCount;
// 创建一个BitSet实例,用于记录要被删除记录的索引
final BitSet removeSet = new BitSet(size);
final int expectedModCount = modCount;
// 遍历当前Vector的对象数组
for (int i=0; modCount == expectedModCount && i < size; i++) {
@SuppressWarnings("unchecked")
// 取出当前位置的元素
final E element = (E) elementData[i];
// 对当前位置的元素执行给定的条件判断
if (filter.test(element)) {
// 如果判断的结果为true,则记录当前索引
removeSet.set(i);
removeCount++;
}
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
// shift surviving elements left over the spaces left by removed elements
// 将未删除的元素向左移
final boolean anyToRemove = removeCount > 0;
if (anyToRemove) {
// 计算出剩余后的元素个数
final int newSize = size - removeCount;
// 遍历对象数组,i代表了原数组索引,j代表新数组索引
for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
// 取出i及以后的第一个未被删除的元素的索引
i = removeSet.nextClearBit(i);
// 将该未被删除的元素放置到j位置
elementData[j] = elementData[i];
}
// 遍历新对象数组(指完成元素移动后的数组),将后部的元素置为null
for (int k=newSize; k < size; k++) {
elementData[k] = null; // Let gc do its work
}
elementCount = newSize;
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
return anyToRemove;
}
对每个元素执行给定的操作,并用得到的返回值替换该元素。
源码如下:
@Override
@SuppressWarnings("unchecked")
public synchronized void replaceAll(UnaryOperator<E> operator) {
Objects.requireNonNull(operator);
final int expectedModCount = modCount;
final int size = elementCount;
// 遍历对象数组
for (int i=0; modCount == expectedModCount && i < size; i++) {
// 对当前元素执行给定的操作,用计算出的结果替换当前元素
elementData[i] = operator.apply((E) elementData[i]);
}
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
使用给定的比较器对当前Vector
进行排序。
源码如下:
@SuppressWarnings("unchecked")
@Override
public synchronized void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
// 使用Arrays.sort方法对对象数组进行排序
Arrays.sort((E[]) elementData, 0, elementCount, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
在此列表的元素上创建一个“延迟绑定”、“快速失败”的拆分器。
该拆分器报告的特征有:Spliterator#SIZED
、Spliterator#SUBSIZED
、Spliterator#ORDERED
。覆盖该实现时应该记录附加的特征值的报告。
源码如下:
@Override
public Spliterator<E> spliterator() {
// 返回一个VectorSpliterator实例
return new VectorSpliterator<>(this, null, 0, -1, 0);
}
Vector
的拆分器,类似于ArrayList
的拆分器。
当前拆分器所持有的Vector
实例。
当前拆分器所持有的Vector
实例(即上面的list
)的元素数据数组(elementData
)。
当前索引,在前进和拆分时修改。
在使用前一直为-1
;然后是从1
到最后一个索引。
设置围栏(fence
)时初始化该值。
创建覆盖给定范围的新拆分器,也是当前拆分器类的唯一构造函数。
源码如下:
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() { // initialize on first use
int hi;
// 围栏小于0才执行初始化,否则直接返回当前的围栏值
if ((hi = fence) < 0) {
synchronized(list) {
// 初始化array属性,将其值置为列表的元素数据数组
array = list.elementData;
// 期望修改次数置为列表的修改次数
expectedModCount = list.modCount;
// 将围栏设置为列表的元素个数
hi = fence = list.elementCount;
}
}
return hi;
}
执行拆分。
源码如下:
public Spliterator<E> trySplit() {
// 获取围栏位置、当前索引位置,然后基于这俩计算出从当前索引至围栏位置的中间位置
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
// 只有当当前索引小于上面计算出的中间位置时拆分才有意义,所以,不满足时不会进行拆分
return (lo >= mid) ? null :
// 如果需要拆分时,创建一个新的VectorSpliterator实例,其范围为当前索引至中间位置
// 同时index = mid这一步,将当前拆分器的当前索引位置推后至中间位置
// 至此,完成拆分
new VectorSpliterator<E>(list, array, lo, index = mid,
expectedModCount);
}
对当前索引位置的元素执行给定的操作,然后将当前索引右移一位(即加一)。
源码如下:
@SuppressWarnings("unchecked")
public boolean tryAdvance(Consumer<? super E> action) {
int i;
if (action == null)
throw new NullPointerException();
// 当前索引不可大于等于围栏位置
if (getFence() > (i = index)) {
// 上面已经取出了当前索引的位置,赋值给了i,此处对当前索引进行右移操作,即加一
index = i + 1;
// 对i位置的元素执行给定的操作
action.accept((E)array[i]);
if (list.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
return false;
}
对当前拆分器的剩余元素依次执行给的操作。
源码如下:
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action) {
int i, hi; // hoist accesses and checks from loop
Vector<E> lst; Object[] a;
if (action == null)
throw new NullPointerException();
// list不可为空
if ((lst = list) != null) {
// 如果围栏小于0,则重新获取围栏
if ((hi = fence) < 0) {
synchronized(lst) {
expectedModCount = lst.modCount;
a = array = lst.elementData;
hi = fence = lst.elementCount;
}
}
else
a = array;
// 如果数组不为空 且 当前索引大于等于0 且 围栏位置小于等于数组长度,则遍历数组
// 此处有个隐秘操作:index = hi,这一步将当前索引位置推至围栏位置,这样就不用每遍历到一个元素就对index进行加1了
if (a != null && (i = index) >= 0 && (index = hi) <= a.length) {
// 遍历数组,从当前索引位置到围栏位置
while (i < hi)
// 依次执行给定操作
action.accept((E) a[i++]);
if (lst.modCount == expectedModCount)
return;
}
}
throw new ConcurrentModificationException();
}
获取剩余元素的预估个数。
源码如下:
public long estimateSize() {
// 围栏位置减去当前索引位置
return (long) (getFence() - index);
}
获取当前拆分器报告的特征值。
源码如下:
public int characteristics() {
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}