1、概述
我以为Vector貌似使用的并不是很多,如果想学习该集合,一定要把ArrayList集合看明白,因为两者相同的太多了。
在学习Vector集合的时候,我们可以简单的理解成加了锁的ArrayList。由于与ArrayList数据结构相同,所以我们接下来的讲解都是与ArrayList做比较。
Vector集合始于JDK1.0,在JDK1.2的时候,该类改进了List接口,使其成为了Java Collections的成员。所以Vector集合中很多之前写的方法都因为实现了List接口中的方法而被抛弃使用,因为后者使用太简单!!!
2、基本组成
2.1、成员方法
1、用来存放数据的集合
protected Object[] elementData;
2、集合元素的个数
protected int elementCount;
3、容量的增量判定数,用于扩容处的判定
protected int capacityIncrement;
2.2、构造方法
1、空参构造方法
public Vector() {
//默认初始容量为10
this(10);
}
2、初始化集合的时候,传入指定的容量
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
3、初始化集合的时候,传入指定的容量以及容量的增量判定数
public Vector(int initialCapacity, int capacityIncrement) {
super();
//初始化集合小于0,就抛出异常
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
//新建一个长度为initialCapacity的数组,再赋值给elementData
this.elementData = new Object[initialCapacity];
//获取制定的容量增量的判定数
this.capacityIncrement = capacityIncrement;
}
2.3、成员方法
由于分析的思路和ArrayList的思路基本相同,所以我这里只分析几个我觉得典型的方法
1、增加数据(使用add方法的时候,会跳转到这个方法)
public synchronized void insertElementAt(E obj, int index) {
//如果传入的数据不符合规范,我们就抛出异常
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
//操作数+1
modCount++;
//获取到集合的数据个数
final int s = elementCount;
//拿到现有的集合数据
Object[] elementData = this.elementData;
//如果容量不足就扩容
if (s == elementData.length)
elementData = grow();
//与ArrayList使用方式相同,进行数组拷贝
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
//将我们的数据放入,拷贝回来的集合中
elementData[index] = obj;
//集合的个数+1
elementCount = s + 1;
}
2、删除方法
public synchronized void removeElementAt(int index) {
//校验数据是否合法
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
//获取要删除的数据的位置
int j = elementCount - index - 1;
//如果位置大于0,就进行数据的拷贝
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
//集合操作数+1,集合的元素-1
modCount++;
elementCount--;
//将删除的位置赋值为null,方便垃圾回收
elementData[elementCount] = null; /* to let gc do its work */
}
3、修改方法
public synchronized E set(int index, E element) {
//判断数据是否合法
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
//根据对应的index值,拿到对应的数据值,并复制给oldValue
E oldValue = elementData(index);
//设置新的数据值
elementData[index] = element;
//返回oldValue
return oldValue;
}
4、查找方法
public synchronized E get(int index) {
//判断数据是否合法
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
//直接根据index查找,然后返回
return elementData(index);
}
我们不难发现,我们的这四个增删改查方法,都添加了synchronized锁,这也就是Vector的特点之一
3、代码编写上
其实在分析Vector的代码时,我们不难发现它与ArrayList代码风格的不一致性。
ArrayList
public E get(int index) {
Objects.checkIndex(index, size);
checkForComodification();
return root.elementData(offset + index);
}
Vector
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
同样是对于传入index的合法性校验,前者是直接调用其他方法进行,而后者是直接在方法体中进行判定。当然如果让我来写的话,肯定写出来的是后面这一种。但是前者有一个明显的优势就是提高了代码的复用性。对于get方式传入index时的校验方法,在set以及remove方式中都能够使用,继而达到代码复用的效果!!!
当然还有很多方法的
4、总结
特点:
-
采用动态数组的方式实现,默认的构造方法创建容量为10的集合
-
完成扩容后,新的集合的容量是旧集合的两倍
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
-
由于是动态数组的数据结构,所以依然不适合做删除或者插入
-
为了防止扩容带来的性能损耗和空间上的浪费,建议在初始化集合的时候,给出指定的容量
-
由于方法使用了synchronized锁,所以是线程安全的,也正是如此,在单线程情况下因为性能的低,所以不建议使用
至此我们关于List接口下的集合就都学习完毕,开心!!!
虽然后面还有很多呀!
Set接口下的:HashSet、TreeSet、LinkHashSet
Map接口下的:HashMap、ConcurrentHashMap、HashTable、TreeMap、LinkHashMap
好吧,一个集合背后的居然要学习十一个类。emmm!!!