一、概述
1.Vector是基于数组实现的一个动态数组,其容量自动增长,与数组一样,它包含可以使用整数索引访问的组件;
2.Vector中的很多方法都加入了同步语句,索引是线程安全的;
3.Stack继承了Vector类,其内部元素是后进先出的,由于继承了Vector类,Stack也是线程安全的。
二、Vector的源码分析
1、Vector简介
(1)继承了AbstractList方法,实现了List,所以是一个队列;
(2)实现了RandomAccess接口,提供了随机访问功能;
(3)Vector的默认容量是10,默认的扩容系数是0,当扩容系数是0时,扩容时是直接进行翻倍。
2、Vector中的变量和初始化函数
Vector实际上是通过数组去保存数据的,Vector的默认容量是10,由于Vector是自动扩容的,在构造函数中会置顶扩容系数,默认扩容系数是0,如果扩容系数大于0,则将数组容量增加扩容系数大小,否则是将容量进行翻倍。
//通过数组存放元素
protected Object[] elementData;
//数组中元素的个数
protected int elementCount;
//数组容量扩展的系数,在创建Vector时就需要指定,每次扩容时增加的大小
protected int capacityIncrement;
/**
* Vector的初始化:指定初始化容量和扩容系数
*/
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
//新建一个数组,其容量大小是初始化容量
this.elementData = new Object[initialCapacity];
//设置扩容系数
this.capacityIncrement = capacityIncrement;
}
/**
* Vector的初始化:指定初始化容量,默认扩容系数是0
*/
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
/**
* Vector的初始化:默认的初始化容量是10,默认扩容系数是0
*/
public Vector() {
this(10);
}
/**
* 创建一个包含指定集合元素的Vector
*/
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是动态数组,可以根据数组中的元素的个数进行容量的修改,在进行元素的增加时,都需要对容量进行确认是否需要进行扩容,及ensureCapacity方法和ensureCapacityHelper方法,该方法主要是将当前数组的长度与需要扩容到的容量进行比较,如果当前容量大于指定的容量,则不需要扩容,如果是小于的话,根据当前容量和扩容系数以及指定容量三者共同比较最后决定扩容的大小。在一般情况下都是在修改数组的结构时自动调用该方法进行扩容。
但是也可以在使用过程中手动调用trimToSize去减少数组的容量,该方法是将数组的容量修改为实际元素的个数的大小,减少对空闲空间的占用,如果是在数组中的空闲空间过多且不再进行元素的插入的时候可以调用该元素,如果对数组还存在插入等操作就不必要进行该方法的调用。
/**
* 将Vector的数组的容量设置为实际存储的元素的个数的大小
* 这种情况是为了减少数组占用的空间
* 例如数组容量远大于实际存储的个数时,使用该方法可以减少空闲的空间
*/
public synchronized void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (elementCount < oldCapacity) {
elementData = Arrays.copyOf(elementData, elementCount);
}
}
/**
* 确定Vector的容量
* @param minCapacity
*/
public synchronized void ensureCapacity(int minCapacity) {
if (minCapacity > 0) {
modCount++;
ensureCapacityHelper(minCapacity);
}
}
/**
* 确定Vector的容量:如果minCapacity大于当前数组的长度,那么需要进行数组的扩容
* @param minCapacity
*/
private void ensureCapacityHelper(int minCapacity) {
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
//数组的最大容量
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 扩容的实现
* @param minCapacity
*/
private void grow(int minCapacity) {
//当前数组的容量
int oldCapacity = elementData.length;
//预计扩容后的容量:如果扩容系数大于0,预计扩容后的容量就是当前容量+扩容系数,否则就是当前容量*2
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;
}
4、获取Vector中元素的索引位置
在Vector中根据元素查找其在数组中的位置有以下几个方法,其中indexOf方法是从指定的索引位置,默认是0,从前向后查找,找到第一个等于该元素的位置进行返回,不存在的情况下返回-1。lastIndexOf是返回指定元素在Vector中最后一次出现的索引位置,由于Vector是可以按照索引位置进行查询的,所以这种情况下是从后向前进行遍历查找的。
/**
* 返回某个元素在数组中的索引位置,不包含的话返回-1
* @param o
* @return
*/
public int indexOf(Object o) {
return indexOf(o, 0);
}
/**
* 从index位置向后查找数组中元素o的位置
* @param o
* @param index
* @return
*/
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;
}
/**
* 返回元素o在数组中最后一次出现的索引位置
* @param o
* @return
*/
public synchronized int lastIndexOf(Object o) {
return lastIndexOf(o, elementCount-1);
}
/**
* 从index位置向前查找元素o在数组中出现的位置,从数组尾部向前查询
* @param o
* @param index
* @return
*/
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;
}
5、获取Vector中指定位置的元素
Vector实现了RandomAccess方法,可以按照索引值进行访问,所有对指定索引位置的元素的方法是可以直接访问的,不需要对数组进行遍历等操作,因此其执行速度很快。
/**
* 根据索引index返回该位置上的元素值
* @param index
* @return
*/
public synchronized E elementAt(int index) {
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " + elementCount);
}
return elementData(index);
}
/**
* 返回数组中的第一个元素
* @return
*/
public synchronized E firstElement() {
if (elementCount == 0) {
throw new NoSuchElementException();
}
return elementData(0);
}
/**
* 返回数组中的最后一个元素
* @return
*/
public synchronized E lastElement() {
if (elementCount == 0) {
throw new NoSuchElementException();
}
return elementData(elementCount - 1);
}
/**
* 获取指定位置的元素值
* @param index
* @return
*/
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
6、Vector中的增加、修改、删除元素的操作
在Vector中有多个方法可以对元素进行增加、修改、删除操作。
对于元素的增加操作,在插入时首先都要调用ensureCapacityHelper方法对数组的容量进行判断是否需要进行扩容操作,判断完成之后,才将元素插入进去,如果是指定位置的元素插入,例如insertElementAt(E obj, int index),则还存在元素的复制,需要将index位置后面所有的元素都向后移动一位,而对于不指定位置的插入操作,则是直接将元素放置在数组的尾部,相比较执行操作比较简单,耗时时间也少。
对于元素的修改操作,是将指定位置的元素进行覆盖,不存在修改数组结构,因此不需要进行扩容检查,而是直接进行数组的替换。
对于元素的删除操作,如果是删除指定的元素则是先对数组进行遍历,找到元素在数组中的索引位置,然后删除对应位置的元素,该操作是将索引位置之后的元素都向前移动一位,然后将最后一位置空。
/**
* 设置index位置中的元素为obj
* @param obj
* @param index
*/
public synchronized void setElementAt(E obj, int index) {
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
elementData[index] = obj;
}
/**
* 删除某个索引位置上的元素
* index值必须小于数组中元素的个数值,必须是正数
* 存在数组中元素的复制
* @param index
*/
public synchronized void removeElementAt(int index) {
modCount++;
if (index >= elementCount) {
throw new ArrayIndexOutOfBoundsException(index + " >= " +
elementCount);
}
else if (index < 0) {
throw new ArrayIndexOutOfBoundsException(index);
}
int j = elementCount - index - 1;
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */
}
/**
* 向数组中index位置插入元素obj,存在数组元素的复制
* 需要进行数组扩容的确认
* @param obj
* @param 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++;
}
/**
* 修改index位置元素为element
* @param index
* @param element
* @return
*/
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中的指定位置插入一个元素
* @param index
* @param element
*/
public void add(int index, E element) {
insertElementAt(element, index);
}
/**
* 向数组中增加一个元素,首先进行扩容的确认,然后在数组的尾部插入元素
* @param obj
*/
public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
/**
* 向Vector中增加一个元素
* @param e
* @return
*/
public synchronized boolean add(E e) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
/**
* 删除数组中的某个元素值,删除第一次元素出现的位置
* 首先找到该元素在数组中的位置,然后删除该位置上的元素
* @param obj
* @return
*/
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
/**
* 删除Vector中的元素o
* @param o
* @return
*/
public boolean remove(Object o) {
return removeElement(o);
}
/**
* 删除指定位置的元素,并返回删除的元素值
* @param index
* @return
*/
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
int numMoved = elementCount - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
/**
* 清空数组中的元素
*/
public synchronized void removeAllElements() {
modCount++;
// Let gc do its work
for (int i = 0; i < elementCount; i++)
elementData[i] = null;
elementCount = 0;
}
/**
* 清空Vector中的元素
*/
public void clear() {
removeAllElements();
}
7、Vector中的批量操作
Vector中有一些操作是批量进行的,对于批量操作,其中部分是根据其父类AbstractCollection中的方法进行实现的,例如containAll方法,其操作也是对指定集合中的元素进行遍历,挨个判断是否在Vector中的
/**
* 判断Vector中是否包含指定集合中的所有元素
* @param c
* @return
*/
public synchronized boolean containsAll(Collection<?> c) {
return super.containsAll(c);
}
/**
* 将指定集合中的所有元素插入到Vector中,插入到尾部
* @param c
* @return
*/
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;
}
/**
* 删除Vector中包含指定集合中的所有元素,
* @param c
* @return
*/
public synchronized boolean removeAll(Collection<?> c) {
return super.removeAll(c);
}
/**
* 删除非指定集合中的所有元素
* @param c
* @return
*/
public synchronized boolean retainAll(Collection<?> c) {
return super.retainAll(c);
}
/**
* 在指定位置index插入指定集合c中的所有元素
* @param index
* @param c
* @return
*/
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;
return numNew != 0;
}
8、Vector的遍历
//vector的遍历:Enumeration遍历
Enumeration enums = vector.elements();
while(enums.hasMoreElements()){
System.out.println(enums.nextElement());
}
//随机访问,通过索引值去遍历
for(int i = 0; i< vector.size(); i++){
System.out.println(vector.get(i));
}
//for循环遍历
for(Object i: vector){
System.out.println(i);
}
//iterator遍历
Iterator it = vector.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
9、Vector总结
(1)Vector有四种构造方法,其默认容量是10,默认扩容系数是0;
(2)每次在增加元素时,都需要调用扩容函数ensureCapacityHelper来确保数组的容量是足够的;
(3)大部分方法都加了synchronized同步语句来保证是线程安全的;
(4)Vector中允许存在null元素
三、Stack源码解析
1、Stack简介
Stack继承了Vector类,其内部元素是后进先出的(LIFO),由于继承了Vector类,Stack也是线程安全的
2、Stack的源码分析
//stack构造函数
public Stack() {
}
/**
* 向栈中放入一个元素
* 其实质是调用的Vector中的addElement方法,将元素插入到数组的尾部
*/
public E push(E item) {
addElement(item);
return item;
}
/**
* stack的出栈操作
* 调用peek方法获取栈顶部的元素值,然后调用Vector中的removeElementAt方法,删除数组中的最后一个元素
* @return
*/
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
/**
* 查找栈顶部的对象,无需从栈中取出
* @return
*/
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
/**
* 判断stack是否为空,数组中是否存在元素
* @return
*/
public boolean empty() {
return size() == 0;
}
/**
* 返回某个元素在栈中的位置
* 调用vector的lastIndexOf方法,获取在数组中的索引位置
* 如果索引值大于等于0,那么使用数组长度减去索引值得到在堆栈中的位置,返回-1表示不存在
* @param o
* @return
*/
public synchronized int search(Object o) {
int i = lastIndexOf(o);
if (i >= 0) {
return size() - i;
}
return -1;
}
Stack源码中的方法比较少也比较简单,并且其大部分方法的实现都是依据Vector来进行的,对于体现栈的先进后出的特点是根据push和pop方法体现的,在push中可以看到插入一个元素是调用的vector中的addElement方法,是向数组的尾部插入一个元素,而在pop中是取出数组尾部的元素,然后将尾部的元素进行删除。
3、Stack总结
(1)对Stack的操作都是在数组的一端进行的,出栈和入栈都是在尾部进行操作;
(2)Stack就相当于一个桶,后放进去的要先拿出来