Java 集合框架之 Vector
简介
java.util.Vector
降生于jdk1.0
。
到了jdk1.2
的时候有了“集合框架(Java Collections Framework)”这个概念,并且有一套的实现,而Vector
再被改造后,也成为其中的一员,归属于List
这个子类。
Vector
其实就是一个线程安全的可变数组的容器。容量大小可以根据需要在一定的范围内自动扩张/收缩。凡是都有两面性的,提示了开发效率的同时(使用者无需关心容量的问题),也需要付出一定的代价,那就是牺牲了空间,通过分配较大的内存大小(简单理解就是预付费),来减少扩张的频率。
源码解析
源码基于JDK 1.8u201
,且只关注集合框架相关的api。
类的定义
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
可以看到Vector
是AbstractList
的一个子类,所以说Vector
是“集合框架(Java Collections Framework)”中的一员,并且归属于List
这个小类。
还可以看到Vector
实现类3个标识性的接口。
java.util.RandomAccess
: 这个接口是JDK1.4
的时候出来的。其作用仅仅是标记List
的实现类是能进行随机访问的。看注释看注释看注释。简单带过:随机访问就是可以随机访问容器内的任意位置,其耗费的时间是基本一致的,就像数组访问第一个元素与访问中间的某个元素的两者耗费的时间基本一致。java.lang.Cloneable
: 这个接口是JDK1.0
的时候出来的。按照注释上的说明,其作用仅仅是标记java.lang.Object#clone
是合法的。java.io.Serializable
: 这个接口是JDK1.1
的时候出来的。这个接口说起来很复杂,下回开单章说。
构造器
java.util.Vector
总共提供了4个可用的构造器。
指定初始化容量、扩容的容量值的构造器
/**
* 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) {
// 调用了父类的无参构造器
// 不用看了,两个父类的无参构造器都是空的
// 但是 java.util.AbstractList 这个父类会初始化一个变量: modCount
// 这个字段体现了内部结构的修改次数。
// 这个字段主要用于迭代器(iterator)遍历时,如果有被意外操作的情况,
// 则抛出```java.util.ConcurrentModificationException```异常,
// 也就是```fail-fast```机制。详情手动查看注释。
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
// 创建了一个指定大小的数组,然后赋值给 elementData
this.elementData = new Object[initialCapacity];
// 初始化自定义每次扩容后增加的容量值
// <= 0 时,不起作用;> 0 时,就是每次扩容后增加的容量
// 这个值我感觉挺废的。给小了,扩容频率高;给大了,浪费内存。
this.capacityIncrement = capacityIncrement;
}
指定初始化容量的构造器
/**
* 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);
}
无参构造器
/**
* 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);
}
可以导入数据的构造器
/**
* 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) {
elementData = c.toArray();
elementCount = elementData.length;
// 这个 bug 的完整链接地址: https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652
// 估计只有 java.util.Arrays#asList 才有这个 bug,这个方法返回类型的 toArray() 方法直接转成原生类型的数组
// 而集合类的 toArray() 方法都是 Object[],或者转成 Object[]
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
增删改查之增
添加单个元素: add 方法
/**
* 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) {
// fast-fail机制
modCount++;
// 扩容,详细解析看《其他操作-扩容》小节
ensureCapacityHelper(elementCount + 1);
// 追加当前元素到已存储的最后一个元素后
elementData[elementCount++] = e;
return true;
}
添加多个元素: addAll 方法
/**
* 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++;
// 这块代码其实我觉得可以优化下的,如果 c 为空集合就不需要后面的操作了
Object[] a = c.toArray();
int numNew = a.length;
// 查看《其他操作-扩容》小节
ensureCapacityHelper(elementCount + numNew);
// 扩容后,把集合 c 中的元素复制到当前 elementData 中
System.arraycopy(a, 0, elementData, elementCount, numNew);
elementCount += numNew;
return numNew != 0;
}
插入单个元素: add 方法
/**
* 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.
*
* <p>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.)
*
* <p>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++;
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
// 查看《其他操作-扩容》小节
ensureCapacityHelper(elementCount + 1);
// 注意:复制的时候,源数组和目标数组是同一个,从 index 这个位置开始复制,目标位置为 index + 1,
// 且复制的长度为 elementCount - index,也就是从 index 开始到最后一个有效元素都会被复制
// 也就是说复制完后 index 和 index + 1 这两个位置的数据是一样的,index 之后的数据向后挪动一位
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
// 然后替换掉 index 这个位置的值
elementData[index] = obj;
elementCount++;
}
插入多个元素: addAll 方法
/**
* 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);
// 这块代码其实我觉得可以优化下的,如果 c 为空集合就不需要后面的操作了
Object[] a = c.toArray();
int numNew = a.length;
// 查看《其他操作-扩容》小节
ensureCapacityHelper(elementCount + numNew);
// 这块代码是用于优化的,最终计算出来的是需要迁移数据的个数
// 如果为0,那么就是为最后一个数据,不需要迁移数据,就相当于在尾部添加数据
int numMoved = elementCount - index;
if (numMoved > 0)
// 这一遍复制,是为了提前将数据复制到指定的位置,然后腾出对应的空间给需要插入的数据
System.arraycopy(elementData, index, elementData, index + numNew,
numMoved);
// 复制需要插入的数据
System.arraycopy(a, 0, elementData, index, numNew);
elementCount += numNew;
return numNew != 0;
}
增删改查之删
删除单个元素-根据索引值: remove 方法
/**
* Removes the element at the specified position in this Vector.
* Shifts any subsequent elements to the left (subtracts one from their
* indices). Returns the element that was removed from the Vector.
*
* @throws ArrayIndexOutOfBoundsException if the index is out of range
* ({@code index < 0 || index >= size()})
* @param index the index of the element to be removed
* @return element that was removed
* @since 1.2
*/
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
// 这块代码是用于优化的,最终计算出来的是需要迁移数据的个数
// 如果为0,那么就是为最后一个数据,不需要迁移数据,只要将改为置为 null 就行了
int numMoved = elementCount - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
// 去除当前数组对最后一个元素的引用
// 首先最后一个元素有两种情况:
// 1. 就是要删除的元素
// 2. 非要删除的元素,那么从 index+1 后的所有数据都会被迁移到前一个位置,最后一个和最后第二个元素是重复的,so...
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
删除单个元素-根据值: remove 方法
/**
* 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
*/
public boolean remove(Object o) {
return removeElement(o);
}
/**
* Removes the first (lowest-indexed) occurrence of the argument
* from this vector. If the object is found in this vector, each
* component in the vector with an index greater or equal to the
* object's index is shifted downward to have an index one smaller
* than the value it had previously.
*
* <p>This method is identical in functionality to the
* {@link #remove(Object)} method (which is part of the
* {@link List} interface).
*
* @param obj the component to be removed
* @return {@code true} if the argument was a component of this
* vector; {@code false} otherwise.
*/
public synchronized boolean removeElement(Object obj) {
modCount++;
// 见《查询索引值(从前往后匹配到的第一个元素): indexOf 方法》
int i = indexOf(obj);
if (i >= 0) {
// 这个方法不分析了,与《删除单个元素-根据索引值: remove 方法》逻辑是一样的
removeElementAt(i);
return true;
}
return false;
}
这个方法先根据元素获取索引值,然后根据索引值来删除元素。
删除多个元素: removeAll 方法
removeAll
方法与retainAll
方法的逻辑很像,前者是移除指定的元素,后者是保留指定的元素。
/**
* Removes from this Vector all of its elements that are contained in the
* specified Collection.
*
* @param c a collection of elements to be removed from the Vector
* @return true if this Vector changed as a result of the call
* @throws ClassCastException if the types of one or more elements
* in this vector are incompatible with the specified
* collection
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this vector contains one or more null
* elements and the specified collection does not support null
* elements
* (<a href="Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @since 1.2
*/
public synchronized boolean removeAll(Collection<?> c) {
return super.removeAll(c);
}
/**
* {@inheritDoc}
*
* <p>This implementation iterates over this collection, checking each
* element returned by the iterator in turn to see if it's contained
* in the specified collection. If it's so contained, it's removed from
* this collection with the iterator's <tt>remove</tt> method.
*
* <p>Note that this implementation will throw an
* <tt>UnsupportedOperationException</tt> if the iterator returned by the
* <tt>iterator</tt> method does not implement the <tt>remove</tt> method
* and this collection contains one or more elements in common with the
* specified collection.
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*
* @see #remove(Object)
* @see #contains(Object)
*/
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
if (c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
可以看到java.util.Vector#removeAll
调用的是父类的方法,最终调用的是java.util.AbstractCollection#removeAll
,而其实现中有几个模板方法:java.util.AbstractCollection#iterator
, java.util.Iterator#hasNext
, java.util.Iterator#next
, java.util.Collection#contains
, java.util.Iterator#remove
。
删除多个元素-根据判断条件: removeIf 方法 todo
删除多个元素-只保留给定的元素: retainAll 方法
removeAll
方法与retainAll
方法的逻辑很像,前者是移除指定的元素,后者是保留指定的元素。
/**
* Retains only the elements in this Vector that are contained in the
* specified Collection. In other words, removes from this Vector all
* of its elements that are not contained in the specified Collection.
*
* @param c a collection of elements to be retained in this Vector
* (all other elements are removed)
* @return true if this Vector changed as a result of the call
* @throws ClassCastException if the types of one or more elements
* in this vector are incompatible with the specified
* collection
* (<a href="Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if this vector contains one or more null
* elements and the specified collection does not support null
* elements
* (<a href="Collection.html#optional-restrictions">optional</a>),
* or if the specified collection is null
* @since 1.2
*/
public synchronized boolean retainAll(Collection<?> c) {
return super.retainAll(c);
}
/**
* {@inheritDoc}
*
* <p>This implementation iterates over this collection, checking each
* element returned by the iterator in turn to see if it's contained
* in the specified collection. If it's not so contained, it's removed
* from this collection with the iterator's <tt>remove</tt> method.
*
* <p>Note that this implementation will throw an
* <tt>UnsupportedOperationException</tt> if the iterator returned by the
* <tt>iterator</tt> method does not implement the <tt>remove</tt> method
* and this collection contains one or more elements not present in the
* specified collection.
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*
* @see #remove(Object)
* @see #contains(Object)
*/
public boolean retainAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
Iterator<E> it = iterator();
while (it.hasNext()) {
if (!c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
可以看到java.util.Vector#retainAll
调用的是父类的方法,最终调用的是java.util.AbstractCollection#retainAll
,而其实现中有几个模板方法:java.util.AbstractCollection#iterator
, java.util.Iterator#hasNext
, java.util.Iterator#next
, java.util.Collection#contains
, java.util.Iterator#remove
。
增删改查之改
替换单个元素: set 方法
/**
* Replaces the element at the specified position in this Vector with the
* specified element.
*
* @param index index of the element to replace
* @param element element to be stored at the specified position
* @return the element previously at the specified position
* @throws ArrayIndexOutOfBoundsException if the index is out of range
* ({@code index < 0 || index >= size()})
* @since 1.2
*/
public synchronized E set(int index, E element) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
这个方法没啥好说的,就是将原值设置为新值,并返回原值。
替换多个元素: replaceAll 方法
@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++;
}
这个方法增加了modCount
的判断,其实刚开始我是觉得有点奇怪,为啥要有这个判断呢???迭代器!!!(看modCount
的注释)
然后看看核心代码:
for循环
然后重新赋值,新值的来源为operator.apply((E) elementData[i])
,这时要看参数了,这个接口是jdk1.8新增的,可以直接当成java.util.function.Function
,传入原值,返回处理后的新值。
最后对modCount
进行了自增。(暂时还没理解为啥要加这段)
增删改查之查
查询元素: get 方法
/**
* Returns the element at the specified position in this Vector.
*
* @param index index of the element to return
* @return object at the specified index
* @throws ArrayIndexOutOfBoundsException if the index is out of range
* ({@code index < 0 || index >= size()})
* @since 1.2
*/
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
@SuppressWarnings("unchecked")
E elementData(int index) {
return (E) elementData[index];
}
可以看到,其实最终就是通过索引值来取值。
查询索引值(从前往后匹配到的第一个元素): indexOf 方法
/**
* Returns the index of the first occurrence of the specified element
* in this vector, or -1 if this vector does not contain the element.
* More formally, returns the lowest index {@code i} such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*
* @param o element to search for
* @return the index of the first occurrence of the specified element in
* this vector, or -1 if this vector does not contain the element
*/
public int indexOf(Object o) {
return indexOf(o, 0);
}
/**
* Returns the index of the first occurrence of the specified element in
* this vector, searching forwards from {@code index}, or returns -1 if
* the element is not found.
* More formally, returns the lowest index {@code i} such that
* <tt>(i >= index && (o==null ? get(i)==null : o.equals(get(i))))</tt>,
* or -1 if there is no such index.
*
* @param o element to search for
* @param index index to start searching from
* @return the index of the first occurrence of the element in
* this vector at position {@code index} or later in the vector;
* {@code -1} if the element is not found.
* @throws IndexOutOfBoundsException if the specified index is negative
* @see Object#equals(Object)
*/
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;
}
return -1;
}
indexOf(Object o)
这个方法是集合框架的api,内部调用了java.util.Vector#indexOf(java.lang.Object, int)
方法,由于Vector
可以存储null
,所以做了额外的处理,而index
参数可以设置起始匹配的位置。
最终的结果:
- -1: 元素不存在
- 从前往后匹配到的首个元素的索引值
查询索引值(从后往前匹配到的第一个元素): lastIndexOf 方法
/**
* Returns the index of the last occurrence of the specified element
* in this vector, or -1 if this vector does not contain the element.
* More formally, returns the highest index {@code i} such that
* <tt>(o==null ? get(i)==null : o.equals(get(i)))</tt>,
* or -1 if there is no such index.
*
* @param o element to search for
* @return the index of the last occurrence of the specified element in
* this vector, or -1 if this vector does not contain the element
*/
public synchronized int lastIndexOf(Object o) {
return lastIndexOf(o, elementCount-1);
}
* Returns the index of the last occurrence of the specified element in
* this vector, searching backwards from {@code index}, or returns -1 if
* the element is not found.
* More formally, returns the highest index {@code i} such that
* <tt>(i <= index && (o==null ? get(i)==null : o.equals(get(i))))</tt>,
* or -1 if there is no such index.
*
* @param o element to search for
* @param index index to start searching backwards from
* @return the index of the last occurrence of the element at position
* less than or equal to {@code index} in this vector;
* -1 if the element is not found.
* @throws IndexOutOfBoundsException if the specified index is greater
* than or equal to the current size of this vector
*/
public synchronized int lastIndexOf(Object o, int index) {
if (index >= elementCount)
throw new IndexOutOfBoundsException(index + " >= "+ elementCount);
if (o == null) {
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;
}
return -1;
}
lastIndexOf(Object o)
这个方法是集合框架的api,内部调用了java.util.Vector#lastIndexOf(java.lang.Object, int)
方法,由于Vector
可以存储null
,所以做了额外的处理,而index
参数可以设置起始匹配的位置。
最终的结果:
- -1: 元素不存在
- 从后往前匹配到的首个元素的索引值
查询已存储的数量: size 方法
/**
* Returns the number of components in this vector.
*
* @return the number of components in this vector
*/
public synchronized int size() {
return elementCount;
}
这个方法直接返回elementCount
,而其定义也没啥可说的,重点在与新增、删除操作时对他的修改,详情看其对应的小节。
查询是否为空的Vector
: isEmpty 方法
/**
* Tests if this vector has no components.
*
* @return {@code true} if and only if this vector has
* no components, that is, its size is zero;
* {@code false} otherwise.
*/
public synchronized boolean isEmpty() {
return elementCount == 0;
}
这个方法判断逻辑就是:是否有元素存储在当前实例中。
查询是否包含: contains 方法
/**
* Returns {@code true} if this vector contains the specified element.
* More formally, returns {@code true} if and only if this vector
* contains at least one element {@code e} such that
* <tt>(o==null ? e==null : o.equals(e))</tt>.
*
* @param o element whose presence in this vector is to be tested
* @return {@code true} if this vector contains the specified element
*/
public boolean contains(Object o) {
return indexOf(o, 0) >= 0;
}
这个方法最终调用的是java.util.Vector#indexOf(java.lang.Object, int)
方法,看对应的小节。
查询是否包含全部元素: containsAll 方法
/**
* Returns true if this Vector contains all of the elements in the
* specified Collection.
*
* @param c a collection whose elements will be tested for containment
* in this Vector
* @return true if this Vector contains all of the elements in the
* specified collection
* @throws NullPointerException if the specified collection is null
*/
public synchronized boolean containsAll(Collection<?> c) {
return super.containsAll(c);
}
这个方法最终调用的是父类(java.util.AbstractCollection
)的containsAll
方法:
/**
* {@inheritDoc}
*
* <p>This implementation iterates over the specified collection,
* checking each element returned by the iterator in turn to see
* if it's contained in this collection. If all elements are so
* contained <tt>true</tt> is returned, otherwise <tt>false</tt>.
*
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @see #contains(Object)
*/
public boolean containsAll(Collection<?> c) {
for (Object e : c)
if (!contains(e))
return false;
return true;
}
是个模板方法,回过头来看java.util.Vector#contains
方法,看对应的小节。
其他操作
扩容
/**
* 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 code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
/**
* 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;
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) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
扩容机制的检测入口就是添加数据的时候,因为只有添加数据时才会出现容量不够的情况。源码的入口为java.util.Vector#ensureCapacityHelper
。
- 备注:
Vector
对外提供了可以进行扩容的其他2个方法,自己根据ensureCapacityHelper
反向跟踪。
先来看看ensureCapacityHelper
方法:
if (minCapacity - elementData.length > 0)
,这个判断为true
时才有可能进行扩容,而其情况有两种:
minCapacity
比elementData.length
大- [忽略这种情况]。
minCapacity
为负数,minCapacity - elementData.length
溢出了,变成正数
然后来看看grow
方法:
// 如果设置了 capacityIncrement,则新容量增长量就是 capacityIncrement
// 否则新容量为原来的一倍
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
// newCapacity - minCapacity < 0
// 如果出现这种情况,那么表示:
// 1. 批量添加。如果是一个个添加的话,新容量肯定是会大于添加后的容量
// 2. [忽略这种情况]。还有一种情况就是 minCapacity 为负数,newCapacity - minCapacity 溢出,变成负数
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// newCapacity - MAX_ARRAY_SIZE > 0
// 出现这种情况,那么表示:
// 1. newCapacity 为正数,且大于 MAX_ARRAY_SIZE
// 2. newCapacity 为负数,且 newCapacity - MAX_ARRAY_SIZE 溢出后为正数
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
再来看看hugeCapacity
方法:
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 从 hugeCapacity 这个名字就可以看出,这个方法计算的容量值很大
private static int hugeCapacity(int minCapacity) {
// 这里检测到最终的新容量是否为负数,所以前面说忽略为负数的情况
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
// 最终的容量不是 MAX_ARRAY_SIZE 就是 Integer.MAX_VALUE
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
}
最后再回过头来看grow
的最后一行代码:
elementData = Arrays.copyOf(elementData, newCapacity);
这行代码最终调用的一个native
方法:java.lang.System#arraycopy
,这里不做解析,就是复制原数组的数据到新容量的数组中。
疑惑
为何说Vector
是线程安全的
Vector
对外提供的每个普通方法都是同步的(synchronized
),但是如果一个功能块调用多个普通方法时,还是有点问题的。比如:(仅仅只是举例)多线程下判断Vector
是否为空,如果为空则添加一个元素。两个线程排队执行isEmpty
方法,执行完了就让出“Object monitor”了,所以在还没add
前,理论上两个线程都有可能通过isEmpty
方法,最有可能会添加两个元素。这时候还是需要在这多个方法外部套上synchronized
来保证最终的线程安全。
疑惑1: 集合类已经继承了抽象的集合类了,为啥还要实现接口类?
首先先看下类定义:
public class Vector<E>
extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
...
是不是觉得很奇怪,已经继承了AbstractList
,为啥还要实现List
接口?
如果你仔细找的话,发现集合框架中绝大部分的集合类都是这样做的。
我想真正的原因除了原作者外,估计没人知道了,stackoverflow上有一个话题就是关于这个的。
我的猜想:这样做的好处是,当前类能直接拿到接口信息,也就是通过反射机制Class<?>[] interfaces = Vector.class.getInterfaces();
能直接拿到接口信息,至于有啥用的话,目前我只知道jdk的动态代理(必须实现接口)。