一、Vector的概念
1.vector实现了一个可以自动增长的对象数组,类似于动态数组,能够动态的调整自身的大小,能够根据索引进行查询;
2.vector继承了AbstractList,实现了List,是一个队列,实现了相应的增删改查等功能;
3.vector实现了RnadomAccess接口,因此能够对数据进行随机访问;
4.vector的操作是线程安全的,Vector中的大部分方法增加了ychronized关键字修饰;
二、Vector的源码分析
1.Vector中的成员变量
elementData是一个数组类型,初始化的大小是10,会随着元素的增多不断的增长。
elementCount是数组中元素的个数。
capacityIncrement是数组在扩容时增长的系数,如果不指定这个系数的大小时,默认为0,如果capacityIncrement<=0时,那么每次扩容elementData的时候就是直接翻倍。
protected Object[] elementData;
protected int elementCount;
protected int capacityIncrement;
2.Vector的初始化
Vector的初始化有四种方法:
默认情况下初始化elementData数组的大小为10,capacityIncrement扩容系数为0,在使用时也可以自己指定这几个参数的大小,但是数组的大小必须是正数。
当初始化指定的集合时,数组的中的元素为集合中的元素,数组的大小为集合的大小。
//不指定任何参数时,默认数组的大小为10
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;
}
//初始化指定的集合
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
3.Vector中增加和减少数组大小
在Vector中由于数据量是不固定大小的,当数据量超过当前的容量时,需要对数组的容量进行扩容。每次扩容的大小是由三个参数来决定的:扩容的目标大小minCapacity、扩容系数capacityIncrement以及当前数组的容量大小,如果目标大小小于当前数组的容量,就不需要再进行扩容操作,否则先将数组的容量按照capacityIncrement进行扩容,若扩容后的大小仍小于目标大小,那么就将容量大小改为目标大小。
注意:在后面的方法中也可以看到,每次对Vector进行结构改变的操作,例如insert、add等都会执行ensyreCapacityHelper方法对Vector的容量进行检查,而在进行扩容操作时存在数组的复制等操作,因此如果存在插入大量元素的操作时,可以提前执行一次扩容操作,减少执行ensureCapacityHelper的操作,可以提高Vector中某些方法的执行效率。
在每次执行增加元素的操作时,方法会自动调用ensureCapacityHelper的操作,使用者可以不用去担心容量是否够用,但是如果Vector的容量远大于其中存储的元素的个数时,也会存在空间的浪费,那么就可以调用trimSize方法,对Vector的中未使用到的空间进行释放。
//减少数组占用的空间:当数组中实际存储的元素个数小于数组的容量时,可以减少数组的容量为实际存储元素大小的容量--存在元素的复制
public synchronized void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (elementCount < oldCapacity) {
elementData = Arrays.copyOf(elementData, elementCount);
}
}
//扩展数组的容量大小为指定的minCapacity大小,如果数组的容量小于指定的容量,先按照capacityIncrement系数进行扩容,如果还是小于指定的容量,则扩容到指定的容量
//如果数组中要一次性增加大量元素时,可以先调用这个方法对数组进行扩容,避免在每次add时去扩容,减少扩容的次数
public synchronized void ensureCapacity(int minCapacity) {
modCount++;
ensureCapacityHelper(minCapacity);
}
//对数组进行扩容,这个方法不是同步的,该类中的同步方法可以在内部调用这个,确保生产能力但是不花费额外的成本去进行同步--存在元素的复制
private void ensureCapacityHelper(int minCapacity) {
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object[] oldData = elementData;
int newCapacity = (capacityIncrement > 0) ?(oldCapacity + capacityIncrement) : (oldCapacity * 2);
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
4.Vector中的遍历方法
Vector主要有四种遍历方法:
//通过Iterator进行遍历
Object obj = null;
Iterator<Object> iter = vector.iterator();
while(iter.hasNext()) {
obj = iter.next();
}
//随机访问,通过索引进行遍历
Object obj1 = null;
int size = vector.size();
for(int i = 0; i< size; i++) {
obj1 = vector.get(i);
}
//通过for循环遍历
Object obj2 = null;
for(Object o : vector) {
obj2 = o;
}
//通过Enumeration遍历
Object obj3 = null;
Enumeration enumer = vector.elements();
while(enumer.hasMoreElements()) {
obj3 = enumer.nextElement();
}
测试这四种方法遍历的效率:
public static void VectorTest1() {
Vector vector = new Vector();
long s1 = System.currentTimeMillis();
for(int i = 0; i< 10000000; i++) {
vector.add(i);
}
//System.out.println("初始化时间:"+(System.currentTimeMillis()-s1));
s1 = System.currentTimeMillis();
//通过Iterator进行遍历
Object obj = null;
Iterator<Object> iter = vector.iterator();
while(iter.hasNext()) {
obj = iter.next();
}
System.out.println("iterator花费时间:"+(System.currentTimeMillis()-s1));
s1 = System.currentTimeMillis();
//随机访问,通过索引进行遍历
Object obj1 = null;
int size = vector.size();
for(int i = 0; i< size; i++) {
obj1 = vector.get(i);
}
System.out.println("索引遍历花费时间:"+(System.currentTimeMillis()-s1));
s1 = System.currentTimeMillis();
Object obj2 = null;
for(Object o : vector) {
obj2 = o;
}
System.out.println("for循环花费时间:"+(System.currentTimeMillis()-s1));
s1 = System.currentTimeMillis();
//通过Enumeration遍历
Object obj3 = null;
Enumeration enumer = vector.elements();
while(enumer.hasMoreElements()) {
obj3 = enumer.nextElement();
}
System.out.println("Enumeration花费时间:"+(System.currentTimeMillis()-s1));
}
5.Vector中其他的主要方法
方法 | 说明 | 备注 |
---|---|---|
void setSize(int newSize) | 修改vector中包含的元素的个数 | 如果newSize小于当前vector的size,对vector进行截取, 只保留newSize个; 如果大于则先扩容,然后重置vector大小 |
int capacity() | 返回当前vector的容量大小 | |
int size() | 返回当前vector包含的元素个数 | |
boolean isEmpty() | 判断vector是否为空 | |
boolean contains(Object o) | 判断Vector中是否包含元素o | 对Vector进行遍历获取 |
int indexOf(Object o) | 返回Vector中元素o的索引位置 | 对Vector进行遍历,返回第一个包含元素o的位置 |
int indexOf(Object o, int index) | 从index位置开始查询,返回元素o的位置 | 直接从数组的尾部向前遍历,第一次出现的位置 |
int lastIndexOf(Object o, int index) | 从index位置向前查询,最后一次 | |
E elementAt(int index) E get(int index) | 返回index位置的元素值 | 需要对index进行边界校验,直接根据索引取元素值班,效率高 |
E firstElement() | 返回第一个元素值 | 直接去index=0位置的值 |
E lastElement() | 返回最后一个元素值 | |
void setElementAt(E obj, int index) | 修改index位置的元素值为obj | |
void removeElementAt(int index) | 删除index位置的元素值 | 需要进行边界校验,存在数组的复制, 将index位置之后的所有元素向前移动一位,数据量大时效率较高 |
void insetElementAt(E obj, int index) void add(int index, E element) | 插入一个元素在index位置 | 需要进行index的边界校验 vector需要进行扩容操作 存在数组的移动复制 |
void addElement(E obj) boolean add(E e) | 在数组的最后插入一个元素 | vector进行扩容操作,直接插入到最后的位置 与insertElementAt方法相比效率较高 |
boolean removeElement(Object obj) boolean remove(Object o) | 删除一个元素 | 首先调用indexOf方法获取元素所在的位置,然后进行删除 ,也存在数组的移动和复制操作 |
Object[] toArray() | 将vector转化为数组 | 包含vector中的所有元素 |
<T> T[] toArray(T[] a) | 将vector转化为指定的数组 | 包含vector中的所有元素,如果a的长度大于vector.size ,那么将后面的值用null补齐 |
E set(int index, E element) | 修改index位置的元素值,返回替换前的值 | |
E remove(int index) | 删除index位置的值,返回删除前的值 | 与removeElementAt(int index)相同,区别在于此方法有返回值 |
boolean containsAll(Collection<?> c) | 判断vector中是否包含指定集合中的所有元素 | 对c进行遍历,取c中的值去挨个判断是否在vector中, 只要有一个不再,则返回false |
boolean addAll(Collection<?> c) | 将C中的所有元素加到vector中 | |
boolean retainAll(Collection<?> c) | 判断vector中是否有元素不再C中 | 只要vector中有一个元素不再C中,则返回true |
boolean addAll(int index, Collection<?> c) | 在指定位置插入c中的所有元素 | 存在数组元素的移动和复制,效率较低 |
boolean equals(Object o) | 判断两个集合是否相等 | 一是比较两个集合的类型是否相同 二是比较两个集合中包含的元素个数是否相同 三是比较两个集合中所有的元素值是否相等 |
List<E> subList(int fromIndex, int toIndex) | 截取vector,返回的类型为List, 返回值时索引值为fromIndex-toIndex之间的值 | 需要进行边界校验 |
void removeRange(int fromIndex, int toIndex) | 删除vector中索引值为fromIndex到toIndex之间的元素 | |
三、Vector的使用
Vector为存储的对象分配的是一块连续的存储空间,他的本质上是一个动态数组,可以通过索引进行访问,因此随机访问的效率很高,但是在Vector中插入或删除一个元素时,会对数组中的元素进行复制和移动操作,当Vector中存储的数据量很大的情况下,对元素的进行复制操作时开销比较大。
而List中的元素是以链表的形式存储的,当访问一个元素的时候都需要对链表进行遍历,但是相比较Vector,List的插入和删除元素操作比较方便。
因此Vector比较适用于:对象的数量变化较少,简单对象,随机访问较频繁的情况中,而List比较适用于对象数量变化大,对象比较负责,频繁插入和删除操作的情况。