Java集合中的Vector和Stack是早期线程安全的集合类,但在现今的开发中已经被更高效的方案替代了。
Vector
特点
- 基于动态数组实现,在数组容量不足的时候自动扩容。默认初始容量是10
- 线程安全,方法添加了synchronized锁,确保多线程环境下线程安全
- 自动扩容,默认按照原数据长度的2倍扩容,如果设置了capacityIncrement,则按照自定义容量扩容
- 扩容时是创建了一个新的数组,将旧数据中的数据复制到新数组中
- 同步方法导致性能较低,单线程环境下效率不如ArrayList
使用场景
多线程环境下需要线程安全的动态数组(更推荐CopyOnWriteArrayList
或Collections.synchronizedList
)
方法
构造方法
//传入参数:initialCapacity:初始化容量;capacityIncrement:扩容容量
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
//传入参数:initialCapacity:初始化容量
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
//默认初始化容量为10
public Vector() {
this(10);
}
//传入参数:集合(创建新的数组,将原数组数据复制到新数组)
public Vector(Collection<? extends E> c) {
elementData = c.toArray();
elementCount = elementData.length;
//判断c.toArray()返回的集合是否是Object[]类型,不是则转换为Object[]类型
if (elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData, elementCount, Object[].class);
}
添加元素
尾部添加元素
//在数组尾部添加元素
public synchronized boolean add(E e) {
modCount++;
add(e, elementData, elementCount);
return true;
}
private void add(E e, Object[] elementData, int s) {
if (s == elementData.length)
elementData = grow(); //容量不足扩容
elementData[s] = e;
elementCount = s + 1;
}
指定位置添加元素
//指定位置添加元素
public void add(int index, E element) {
insertElementAt(element, index);
}
//数组中index索引位之后的元素都往后移一位,obj放入index索引位
public synchronized void insertElementAt(E obj, int index) {
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
modCount++;
final int s = elementCount;
Object[] elementData = this.elementData;
if (s == elementData.length)
//容量不足,扩容
elementData = grow();
//元素后移一位
System.arraycopy(elementData, index,
elementData, index + 1,
s - index);
elementData[index] = obj;
elementCount = s + 1;
}
尾部添加集合
//将传入的集合添加到数组尾部
public boolean addAll(Collection<? extends E> c) {
Object[] a = c.toArray();
modCount++;
int numNew = a.length;
if (numNew == 0)
return false;
synchronized (this) {
Object[] elementData = this.elementData;
final int s = elementCount;
if (numNew > elementData.length - s)
elementData = grow(s + numNew); //容量不足则扩容
System.arraycopy(a, 0, elementData, s, numNew);
elementCount = s + numNew;
return true;
}
}
指定位置添加集合
//将elementData数组index索引位之后的元素,
//从原来的index索引位移动到以index+numNew开始的索引位;
//移动的长度是c.toArray()的长度;移动完后将c.toArray()返回的数据添加到elementData中
public synchronized boolean addAll(int index, Collection<? extends E> c) {
if (index < 0 || index > elementCount)
throw new ArrayIndexOutOfBoundsException(index);
Object[] a = c.toArray();
modCount++;
int numNew = a.length;
if (numNew == 0)
return false;
Object[] elementData = this.elementData;
final int s = elementCount;
if (numNew > elementData.length - s)
elementData = grow(s + numNew); //容量不足则扩容
int numMoved = s - index;
if (numMoved > 0)
System.arraycopy(elementData, index,
elementData, index + numNew,
numMoved);
System.arraycopy(a, 0, elementData, index, numNew);
elementCount = s + numNew;
return true;
}
删除元素
删除指定索引位元素
//删除指定位置元素:index索引位之后的元素前移一位,将index位的元素置为null
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 (原来index位的元素没有强引用之后会被垃圾回收)
return oldValue;
}
删除指定元素
//删除指定元素
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
//查找指定元素的位置
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;
}
//数组index索引位之后的元素前移一位,删除index索引位元素
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;
if (j > 0) {
System.arraycopy(elementData, index + 1, elementData, index, j);
}
modCount++;
elementCount--;
elementData[elementCount] = null; /* to let gc do its work */
}
查询元素
//查询指定索引位元素
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
E elementData(int index) {
return (E) elementData[index];
}
Stack
特点
- 继承自Vector,同样是基于动态数组,并且是线程安全的
- 提供栈操作:push(E item);pop();peek()
- 因为继承自Vector,Stack拥有了Vector中非私有的方法操作权限,比如:insertElementAt(E obj, int index),可以向栈中任意位置添加元素,破环栈结构
- 同步方法导致效率低
使用场景
在多线程环境下需要后进先出(LIFO)操作时使用(但实际场景中更推荐Deque
的实现类)
方法
push(E item)
//实际调用Vector中的addElement方法
public E push(E item) {
addElement(item);
return item;
}
E pop()
//弹出栈顶元素,实际调用Vector中的removeElementAt方法删除尾部元素
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
//Vector中的size方法,获取的是数据的实际元素个数
public synchronized int size() {
return elementCount;
}
E peek()
//获取栈顶元素,实际调用Vector中的elementAt方法获取数组尾部元素
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}