首先我们再来回顾一下List集合框架的具体体现:
从中可以看出,Vector容器是和ArrayList最相似的集合类容器,其父类都是AbstractList类,那Vector到底有什么用?为什么有了ArrayList还要创一个Vector容器呢?那就从源码开始慢慢解读吧。
首先看一看Vector类的结构:
public class Vector<E> extends AbstractList<E>
implements List<E>,RandomAccess,Cloneable,java.io.Serializable
再对比ArrayList类的结构:
public class ArrayList<E> extends AbstractList<E>
implements List<E>,RandomAccess,Cloneable,java.io.Serializable
发现除了类名,其他的都一模一样,同样都是继承了AbstractList,同样都实现了List接口、RandomAccess接口、Cloneable接口和java.io.Serializable接口,这些接口的功能我在我的另一篇博客都已经讨论过,此处就不再赘述了,具体可移步我的另一篇博客:源码解析——ArrayList。
接下来再看Vector的成员变量和常量:
protected Object[] elementData;
//存储vector实际数据的数组
protected int elementCount;
//存储vector数组的实际长度
protected int capacityIncrement;
//进行相关的增长
private static final long serialVersionUID = -2767605614048989439L;
//验证版本是否一致,用于反序列化
此处和ArrayList相比就少了很多东西了,首先它只有一个成员数组elementData、一个存储vector长度的elementCount、一个用于扩容的变量capacityIncrement还有一个作为反序列化的标识serialVersionUID。除此之外,其成员变量的访问权限几乎都是protected而不是像ArrayList那样的全员private;至于protected和private的区别,如下图:
也就是说上面的那些成员变量除了可以被本类中调用,也可以被本类的子类调用。
接下来再看Vector的构造器:
public Vector(int initialCapacity,int capacityIncrement){
//构造器1,传入参数为数组初始大小以及增长系数...这个增长系数怎么算?
super();
if(initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity:"+ initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
public Vector(int initialCapacity){
//构造器2,传入参数是初始大小,所以增长系数默认为0
this(initialCapacity,0);
}
public Vector(){
//构造器3,传入空参,那么默认构造一个长度为10的数组,增长系数为0
this(10);
}
public Vector(Collection<? extends E> c){
//构造器4,如果传的是一个集合,那将其转为数组存入Vector
elementData = c.toArray();
elementCount = elementData.length;
//如果c.toArray返回的不是Object类型的数组,那就转为Object类型
if(elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData,elementCount,Object[].class);
}
Vector容器有四个构造器,但其实仔细分析,其实和ArrayList的构造器类似,主要分为无参构造器、参数是初始大小的构造器、参数是集合的构造器以及还有一个参数是初始大小和增长系数的构造器。这个增长系数是什么东西?有什么作用??为什么可以在构造器中就可以定义了?从字面上来看,这个增长系数应该是和扩容有关的变量,因此先来看一看Vector的核心方法——扩容方法:
public synchronized void ensureCapacity(int minCapacity){
//确认传入容量参数是否合法
if(minCapacity > 0){
modCount++;
ensureCapacityHelper(minCapacity);
}
}
private void ensureCapacityHelper(int minCapacity){
//确认容量辅助方法,如果最小容量大于当前数组长度,那就增长
if(minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity){
//增长方法,和ArrayList类似,不过多了一个capacityIncrement
//ArrayList是首先在原容量上提升1.5倍,此处则先获取增长因素
//如果增长因素设置了,那新容量等于原容量增加增长因素
//否则新容量等于原容量的两倍,再与传入参数进行对比
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){
//如果minCapacity大于int最大值,那就成负数了,所以抛出内存溢出异常
if(minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
自此,应该已经看出了一些ArrayList和Vector的区别了。首先,构造方式不太一样,如果传入空参,那么ArrayList会直接初始化一个空数组,等到需要增加元素了,那么再对成员数组进行扩充,第一次扩充直接扩大10容量,而后每一次扩充先扩原容量的1.5倍,再与传入的参数对比,如果传入的扩容量大于系统自己扩的新容量,那么就按照传入的容量来扩,否则就直接扩1.5倍。
而在Vector容器中,如果传入空参,那么会直接初始化一个容量为10的数组,不会创建空数组。并且创建Vector的时候可以直接传入一个增长因素,这个增长系数运用在每次扩容的时候。当需要扩容时,方法首先会去判断用户是否传入增长系数,如果没传入,即成员变量初始化为0,那么就每次扩容都会增加原容量的两倍,如果传入了,那就每次扩容增加一个增长系数。增加后所得到的新容量再与传入的参数对比,决定最后按照哪个容量进行扩容。
由于Vector对象初始化的时候直接就是长度为10的数组,因此扩容时不需要判断是否数组为空,所以步骤少了很多。
那么为什么ArrayList初始化的时候要创建一个空数组而不是直接创建一个长度为10的数组呢?这个问题我在网上检索了很久,也没有找到一个比较满意的答案。那我直接说说我自己的理解吧,算作抛砖引玉。
我认为ArrayList主打的是快速,以牺牲一部分安全性为代价提高查找速度,而Vector主打的是安全性,就算速度慢一些,但是要保证安全性。所以ArrayList一般用于单线程,而Vector多用于多线程。那么ArrayList为了达到快速的目的,如果直接创建其对象而不传入什么参数的话,它就默认创建空数组,因为这样速度快,只有用到它的时候,它再初始化数组,扩容为10。而Vector为了追求安全性,一开始就创建容量为10的数组,一定程度上防止了空指针异常的发生,但是速度可能就慢了一些。
之后就开始上源码了
public class Vector<E> extends AbstractList<E>
implements List<E>,RandomAccess,Cloneable,java.io.Serializable
{
protected Object[] elementData;
//存储vector实际数据的数组
protected int elementCount;
//存储vector数组的实际长度
protected int capacityIncrement;
//进行相关的增长
private static final long serialVersionUID = -2767605614048989439L;
//验证版本是否一致,用于反序列化
public Vector(int initialCapacity,int capacityIncrement){
//构造器1,传入参数为数组初始大小以及增长系数...这个增长系数怎么算?
super();
if(initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity:"
+ initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
public Vector(int initialCapacity){
//构造器2,传入参数是初始大小,所以增长系数默认为0
this(initialCapacity,0);
}
public Vector(){
//构造器3,传入空惨,那么默认构造一个长度为10的数组,增长系数为0
this(10);
}
public Vector(Collection<? extends E> c){
//构造器4,如果传的是一个集合,那将其转为数组存入Vector
elementData = c.toArray();
elementCount = elementData.length;
//如果c.toArray返回的不是Object类型的数组,那就转一下,不是Object那是什么??
if(elementData.getClass() != Object[].class)
elementData = Arrays.copyOf(elementData,elementCount,Object[].class);
}
public synchronized void copyInto(Object[] anArray){
//拷贝,传入一个anArray数组,将Vector中的数组拷贝到该数组中
//添加了关键字synchronized同步,使本方法是同步的,进程进入方法体
//后获得内置锁,其他线程倘若也想进入本方法必须等前一个线程离开方法松开锁
System.arraycopy(elementData, 0, anArray, 0, elementCount);
}
public synchronized void trimToSize(){
//剪枝,将数组长度压缩到vector真实长度,避免空间浪费
modCount++;
int oldCapacity = elementData.length;
if(elementCount < oldCapacity){
elementData = Arrays.copyOf(elementData,elementCount);
}
}
public synchronized void ensureCapacity(int minCapacity){
//确认传入容量参数是否合法
if(minCapacity > 0){
modCount++;
ensureCapacityHelper(minCapacity);
}
}
private void ensureCapacityHelper(int minCapacity){
//确认容量辅助方法,如果最小容量大于当前数组长度,那就增长
if(minCapacity - elementData.length > 0)
grow(minCapacity);
}
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private void grow(int minCapacity){
//增长方法,和ArrayList类似,不过多了一个capacityIncrement
//ArrayList是首先在原容量上提升1.5倍,此处则先获取增长因素
//如果增长因素设置了,那新容量等于原容量增加增长因素
//否则新容量等于原容量的两倍,再与传入参数进行对比
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){
//如果minCapacity大于int最大值,那就成负数了,所以抛出内存溢出异常
if(minCapacity < 0)
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE)
? Integer.MAX_VALUE
: MAX_ARRAY_SIZE;
}
public synchronized void setSize(int newSize){
//设置vector的新长度,可大可小
modCount++;
if(newSize > elementCount){//如果增大,则进行长度增加操作
ensureCapacityHelper(newSize);
}else{
for(int i = newSize; i < elementCount; i++){
//如果缩小,则将多余的内存释放
elementData[i] = null;
}
}
//设置新的vector容量
elementCount = newSize;
}
public synchronized int capacity(){
//获得vector里面的数组长度,和vector的元素数多少不一定一样
return elementData.length;
}
public synchronized int size(){
//返回vector中的元素数多少
return elementCount;
}
public synchronized boolean isEmpty(){
//判断容器vector是否为空,即元素数是否为0
return elementCount == 0;
}
public Enumeration<E> elements(){
//获取vector中的元素,返回的是枚举类,为什么要用枚举类?安全吗?
return new Enumeration<E>(){
int count = 0;
public boolean hasMoreElements(){//返回是否还有元素
return count < elementCount;
}
public E nextElement(){//获取下一个元素
synchronized(Vector.this){//此处应该是保证了vector元素的安全性
if(count < elementCount){
return elementData(count++);
}
}
throw new NoSuchElementException("Vector Enumeration");
}
};
}
public boolean contains(Object o){
//判断是否含有元素
return indexOf(o,0) >= 0;
}
public int indexOf(Object o){
//获得某元素的索引
return indexOf(o,0);
}
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;
}
public synchronized int lastIndexOf(Object o){
//获取逆序遍历第一次出现某元素的索引
return lastIndexOf(o,elementCount - 1);
}
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;
}
public synchronized E elementAt(int index){
//通过索引获取元素,类似于ArrayList中的get
if(index >= elementCount){
throw new ArrayIndexOutOfBoundsException(index + ">=" + elementCount);
}
return elementData(index);
}
public synchronized E firstElement(){
//获取第一个元素,为什么要有这么一个方法,直接用elementAt(0)不行么??????
if(elementCount == 0)
throw new NoSuchElementException();
return elementData(0);
}
public synchronized E lastElement(){
//获取vector的最后一个元素
if(elementCount == 0){
throw new NoSuchElementException();
}
return elementData(elementCount - 1);
}
public synchronized void setElementAt(E obj, int index){
//通过索引找到并修改位置上的元素
if(index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index + ">=" + elementCount);
elementData[index] = obj;
}
public synchronized void removeElementAt(int index){
//移除vector中的某一个元素
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;//把最后一个内存释放
}
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++;
}
public synchronized void addElement(E obj){
//向vector的末尾加入一个元素,相当于ArrayList中的add
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
public synchronized boolean removeElement(Object obj){
//移除vector中的第一个该元素
modCount++;
int i = indexOf(obj);
if(i >= 0){
removeElementAt(i);
return true;
}
return false;
}
public synchronized void removeAllElements(){
//移除vector中的所有元素
modCount++;
for(int i = 0; i < elementCount; i++)
elementData[i] = null;
elementCount = 0;
}
public synchronized Object clone(){
//克隆并返回和本数组一样的数组,因为是克隆,所以两个是完全一样的数组
//但是其引用是不一样的
try{
@SuppressWarnings("unchecked")
Vector<E> v = (Vector<E>) super.clone();
v.elementData = Arrays.copyOf(elementData,elementCount);
v.modCount = 0;
return v;
}catch(CloneNotSupportedException e){
throw new InternalError(e);
}
}
public synchronized Object[] toArray(){
//将vector集合变为数组输出
return Arrays.copyOf(elementData,elementCount);
}
@SuppressWarinings("unchecked")
public synchronized <T> T[] toArray(T[] a){
//传入一个数组,如果数组容量比集合小,则直接返回本集合的数组输出
//如果数组容量比集合大,则将集合元素复制到数组中,并将数组中多余
//的位置释放,最后返回的是和集合元素数量一样大小的数组
//简单来说,就是传入一个有类型的数组,然后把集合变为数组传出去
//只是后面的数组的类型和传进来的数组类型一致
if(a.length < elementCount)
return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
System.arraycopy(elementData,0,a,0,elementCount);
if(a.length > elementCount)
a[elementCount] = null;
return a;
}
@SuppressWarnings("unchecked")
E elementData(int index){
//获得一个向上转型的元素
return (E) elementData[index];
}
public synchronized E get(int index){
//实现List接口的get方法,和elementAt方法完全一样,推荐使用get方法
if(index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
public synchronized E set(int index,E element){
//这个也和get方法类似,不过与setElementAt方法不一样的地方在于
//此方法可以返回被更新前的元素,推荐使用此方法
if(index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
public synchronized boolean add(E e){
//在vector的末尾插入一个元素
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
public boolean remove(Object o){
//删除某个元素
return removeElement(o);
}
public void add(int index, E element){
//向某个索引的地方插入一个元素,调用的insertElementAt
insertElementAt(element,index);
}
public synchronized E remove(int index){
//对List接口中的remove方法的实现,和removeElement的不同在于
//可以返回被删除的那个元素,建议使用这个方法
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;
return oldValue;
}
public void clear(){
//清空vector中的元素
removeAllElements();
}
public synchronized boolean containsAll(Collection<?> c){
//判断此集合中是否含有传入集合中的全部元素,使用的是
//父类AbstarctList的方法
return super.containsAll(c);
}
public synchronized boolean addAll(Collection<? extends E> c){
//在集合vector末尾插入一个集合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;
}
public synchronized boolean removeAll(Collection<?> c){
//删除vector中在c集合中存在的元素,这里也是调用父类方法
//这里和ArrayList不一样,ArrayList是自己实现
return super.removeAll(c);
}
public synchronized boolean retainAll(Collection<?> c){
//查看vector中是否含有c中的全部元素,也是调用父类方法
//为什么ArrayList不调用父类方法,非要自己实现呢?????
return super.retainAll(c);
}
public synchronized boolean addAll(int index,Collection<? extends E> c){
//在某个索引处插入一个集合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;
}
public synchronized boolean equals(Object o){
//比较两个vector是否一样
return super.equals(o);
}
public synchronized int hashCode(){
//获得此vector的hash值
return super.hashCode();
}
public synchronized String toString(){
//转化为字符串,调用父类方法,此方法ArrayList就没有
return super.toString();
}
public synchronized List<E> subList(int fromIndex,int toIndex){
//返回一个自己的子vector,此处是调用Collections的方法,获得一个
//同样是同步的子vector,和ArrayList不一样,ArrayList是内部类
return Collections.synchronizedList(super.subList(fromIndex,toIndex),this);
}
protected synchronized void removeRange(int fromIndex,int toIndex){
//移除vector中的一部分元素
modCount++;
int numMoved = elementCount - toIndex;
System.arraycopy(elementData,toIndex,elementData,fromIndex,numMoved);
int newElementCount = elementCount - (toIndex - fromIndex);
while(elementCount != newElementCount)]
elementData[--elementCount] = null;
}
private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException{
//将字节流文件读入到vector容器中,具体步骤现在也搞不懂?????????
ObjectInputStream.GetField gfields = in.readFields();
int count = gfields.get("elementCount",0);
Object[] data = (Object[])gfields.get("elementData",null);
if(count < 0 || data == null || count > data.length){
throw new StreamCorruptedException("Inconsistent vector internals");
}
elementCount = count;
elementData = data.clone();
}
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{
//将vector容器内的内容以字节流的方式写入到硬件中,具体步骤??????
//需要注意读入和写入方法都是私有的,只有本类自己才能调用
final java.io.ObjectOutputStream.putField fields = s.putFields();
final Object[] data;
synchronized(this){
fields.put("capacityIncrement",capacityIncrement);
fields.put("elementCount",elementCount);
data = elementData.clone();
}
fields.put("elementData",data);
s.writeFields();
}
public synchronized ListIterator<E> listIterator(int index){
//获取一个数组迭代器,从某一个索引处开始迭代
if(index < 0 || index > elementCount)
throw new IndexOutOfBoundsException("index:" + index);
return new ListItr(index);
}
public synchronized ListIterator<E> listIterator(){
//获取一个数组迭代器,从最开始迭代
return new ListItr(0);
}
public synchronized Iterator<E> iterator(){
//获取一个纯迭代器,只能向后迭代,而且只能从最开始迭代
return new Itr();
}
private class Itr implements Iterator<E>{
//迭代器,内部类,实现和ArrayList基本一致,
//就是更新vector内部数据的时候必须同步
int cursor;
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext(){
return cursor != elementCount;
}
public E next(){
synchronized(Vector.this){
checkForComodification();
int i = cursor;
if(i >= elementCount)
throw new NoSuchElementException();
cursor = i + 1;
return elementData(lastRet = i);
}
}
public void remove(){
if(lastRet == -1)
throw new IllgealStateException();
synchronized(Vector.this){
checkForComodification();
Vector.this.remove(lastRet);
expectedModCount = modCount;
}
cursor = lastRet;
lastRet = -1;
}
@Override
public void forEachRemaining(Consumer<? super E> action){
Objects.requireNonNull(action);
synchronized(Vector.this){
final int size = elementCount;
int i = cursor;
if(i >= size){
return;
}
@SuppressWarnings("unchecked")
final E[] elementData = (E[])Vector.this.elementData;
if(i >= elementData.length){
throw new ConcurrentModificationException();
}
while(i != size && modCount == expectedModCount){
action.accept(elementData[i++]);
}
cursor = i;
lastRet = i - 1;
checkForComodification();
}
}
final void checkForComodification(){
if(modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
final class ListItr extends Itr implements ListIterator<E>{
//数组迭代器,和纯迭代器不同,父类也不一样,方法也不同
//和ArrayList类似,注意同步
ListItr(int index){
super();
cursor = index;
}
public boolean hasPrevious(){
return cursor != 0;
}
public int nextIndex(){
return cursor;
}
public int previousIndex(){
return cursor - 1;
}
public E previous(){
synchronized(Vector.this){
checkForComodification();
int i = cursor - 1;
if(i < 0)
throw new NoSuchElementException();
cursor = i;
return elementData(lastRet = i);
}
}
public void set(E e){
if(lastRet == -1)
throw new IllegalStateException();
synchronized(Vector.this){
checkForComodification();
Vector.this.set(lastRet,e);
}
}
public void add(E e){
int i = cursor;
synchronized (Vector.this){
checkForComodification();
Vector.this.add(i,e);
expectedModCount = modCount;
}
cursor = i + 1;
lastRet = -1;
}
}
@Override
public synchronized void forEach(Consumer<? super E> action){
//使用lambda表达式进行遍历操作
Objects.requireNonNull(action);
final int expectedModCount = modCount;
@SuppressWarnings("unchecked")
final E[] elementData = (E[])this.elementData;
final int elementCount = this.elementCount;
for(int i = 0; modCount == expectedModCount && i < elementCount; i++)
action.accept(elementData[i]);
if(modCount != expectedModCount){
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
pulic synchronized boolean removIf(Predicate<? super E> filter){
//java1.8新特性,没搞懂??????????????
Objects.requireNonNull(filter);
int removeCont = 0;
final int size = elementCount;
final BitSet removeSet = new BitSet(size);
final int expectedModCount = modCount;
for(int i = 0; modCount == expectedModCount && i < size; i++){
@SuppressWarnings("unchecked")
final E element = (E) elementData[i];
if(filter.test(element)){
removeSet.set(i);
removeCount++;
}
}
if(modCount != expectedModCount){
throw new ConcurrentModificationException();
}
final boolean antToRemove = removeCount > 0;
if(anyToRemove){
final int newSize = size - removeCount;
for(int i = 0, j = 0; (i < size)&&(j < newSize); i++,j++){
i = removeSet.nextClearBit(i);
elemntData[j] = elementData[i];
}
for(int k = newSize; k < size; k++){
elementData[k] = null;
}
elementCount = newSize;
if(modCount != expectedModCount){
throw new ConcurrentModificationException();
}
modCount++;
}
return anyToRemove;
}
@Override
@SuppressWarnings("unchecked")
public synchronized void replaceAll(UnaryOperator<E> operator){
//java1.8新特性,应该是替换全部元素之类的,没搞懂??????
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++;
}
@SuppressWarnings("unchecked")
@Override
public synchronized void sort(Comparator<? super E> c){
//对vector的元素进行排序
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData,0,elementCount,c);
if(modCount != expectedModCount){
throw new ConcurrentModificationException();
}
modCount++;
}
@Override
public Spliterator<E> spliterator(){
//获取分割器
return new VectorSpliterator<>(this,null,0,-1,0);
}
static final class VectorSpliterator<E> implements Spliterator<E>{
//分割器,静态内部类,java1.8新特性,没怎么搞懂?????
//和ArrayList的分割器类似
private final Vector<E> list;
private Object[] array;
private int index;
private int fence;
private int expectedModCount;
VectorSpliterator(Vector<E> list, Object[] array,int origin,int fence,
int expectedModCount){
this.list = list;
this.array = array;
this.index = origin;
this.fence = fence;
this.expectedModCount = expectedModCount;
}
private int getFence(){
int hi;
if((hi = fence) < 0){
synchronized(this){
array = list.elementData;
expectedModCount = list.modCount;
hi = fence = list.elementCount;
}
}
return hi;
}
public Spliterator<E> trySplit(){
int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
return (lo >= mid)
? null
:new VectorSpliterator<E>(list,array,lo,index = mid,expectedModCount);
}
@SuppressWarnings("unchecked")
public boolean tryAdvance(Consumer<? super E> action){
int i;
if(action == null)
throw new NullPointerException();
if(getFence() > (i = index)){
index = i + 1;
action.accpet((E)array[i]);
if(list.modCount != expectedModCount)
throw new ConcurrentModificationException();
return true;
}
return false;
}
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> action){
int i,hi;
Vector<E> lst;
Object[] a;
if(action == null)
throw new NullPointerException();
if((lst = list) != null){
if((hi = fence) < 0){
synchronized(lst){
expectedModCount = lst.modCount;
a = array = lst.elementData;
hi = fence = lst.elementCount;
}
}
else
a = array;
if(a != null && (i = index) >= 0 && (index = hi) <= a.length){
while(i < hi)
action.accept((E)a[i++]);
if(lst.modCount == expectedModCount)
return;
}
}
throw new ConcurrentModificationException();
}
public long estimateSize(){
return (long)(getFence() - index);
}
public int characteristics(){
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
}
/**
总结:
Vector 和 ArrayList实现方式基本一致,都是用数组作为基础
其增删改都是建立在重新建立一个数组,然后把现有的数组更新后
的内容复制到新数组中,或者在一个数组内进行复制操作。从而实现
动态扩展容量的功能。
不同的是,vector有很多很老的功能,导致实现接口后又多了一些功能
从而使得有些功能冗余。除此之外,就是vector对外的方法几乎都用
synchronized关键字修饰,从而实现同步操作,保证vector内数据的安全
*/
}
那么,来看看Vector都有哪些主要的并且常用的方法吧
1.trimToSize:
public synchronized void trimToSize(){
//剪枝,将数组长度压缩到vector真实长度,避免空间浪费
modCount++;
int oldCapacity = elementData.length;
if(elementCount < oldCapacity){
elementData = Arrays.copyOf(elementData,elementCount);
}
}
和ArrayList中的trimToSize一样,剪枝,除去成员数组中利用不到的空间,避免空间浪费。
2.capacity与size
public synchronized int capacity(){
//获得vector里面的数组长度,和vector的元素数多少不一定一样
return elementData.length;
}
public synchronized int size(){
//返回vector中的元素数多少
return elementCount;
}
Vector中提供两个获取长度的方法,第一个Capacity主要是返回成员数组中的数组长度,第二个是真正返回vector容器中元素的个数。一般常用size()获取vector的大小。
3.isEmpty
public synchronized boolean isEmpty(){
//判断容器vector是否为空,即元素数是否为0
return elementCount == 0;
}
判断vector容器是否为空,返回的是elementCount而不是成员数组长度!
4.contains与indexOf
public boolean contains(Object o){
//判断是否含有元素
return indexOf(o,0) >= 0;
}
public int indexOf(Object o){
//获得某元素的索引
return indexOf(o,0);
}
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;
}
public synchronized int lastIndexOf(Object o){
//获取逆序遍历第一次出现某元素的索引
return lastIndexOf(o,elementCount - 1);
}
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;
}
此处contains调用了indexOf方法,而indexOf方法实际上也就是循环遍历,返回第一次找到的索引值。
5.toArray
public synchronized Object[] toArray(){
//将vector集合变为数组输出
return Arrays.copyOf(elementData,elementCount);
}
@SuppressWarinings("unchecked")
public synchronized <T> T[] toArray(T[] a){
//传入一个数组,如果数组容量比集合小,则直接返回本集合的数组输出
//如果数组容量比集合大,则将集合元素复制到数组中,并将数组中多余
//的位置释放,最后返回的是和集合元素数量一样大小的数组
//简单来说,就是传入一个有类型的数组,然后把集合变为数组传出去
//只是后面的数组的类型和传进来的数组类型一致
if(a.length < elementCount)
return (T[]) Arrays.copyOf(elementData, elementCount, a.getClass());
System.arraycopy(elementData,0,a,0,elementCount);
if(a.length > elementCount)
a[elementCount] = null;
return a;
}
toArray方法和ArrayList中的toArray方法类似。
6.get
public synchronized E get(int index){
//实现List接口的get方法,和elementAt方法完全一样,推荐使用get方法
if(index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
return elementData(index);
}
public synchronized E elementAt(int index){
//通过索引获取元素,类似于ArrayList中的get
if(index >= elementCount){
throw new ArrayIndexOutOfBoundsException(index + ">=" + elementCount);
}
return elementData(index);
}
这里的get和elementAt方法一模一样,那为什么之前定义了elemnetAt方法还要加一个get方法呢?这里就要涉及到Vector的历史了,在JDK1.2以前还是一个单独的类,所以有很多自己的方法,在JDK1.2以后,vector就被归为Collection中的List框架中了,所以为了实现List接口,就实现了其中的一些方法。正如elementAt就是以前的方法,而get方法时List接口中定义的方法。但是为了一些兼容性的问题,那些老方法也没有删除,但是推荐使用List中的方法,毕竟都是一个体系的。
7.set
public synchronized E set(int index,E element){
//这个也和get方法类似,不过与setElementAt方法不一样的地方在于
//此方法可以返回被更新前的元素,推荐使用此方法
if(index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
public synchronized void setElementAt(E obj, int index){
//通过索引找到并修改位置上的元素
if(index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index + ">=" + elementCount);
elementData[index] = obj;
}
这两个方法也和上面两个方法情况相同,不过这两个方法有不一样的地方,setElementAt不返回任何数值,而set方法返回被更新的原元素。
8.add
public synchronized boolean add(E e){
//在vector的末尾插入一个元素
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
public synchronized void addElement(E obj){
//向vector的末尾加入一个元素,相当于ArrayList中的add
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
同理,add方法为向vector的末尾增加一个元素,因为是增加方法,改变了vector长度,所以需要调用扩容方法,add返回的是boolean型变量,而addElement则不返回任何数值。
9.remove
public boolean remove(Object o){
//删除某个元素
return removeElement(o);
}
public synchronized boolean removeElement(Object obj){
//移除vector中的第一个该元素
modCount++;
int i = indexOf(obj);
if(i >= 0){
removeElementAt(i);
return true;
}
return false;
}
public synchronized E remove(int index){
//对List接口中的remove方法的实现,和removeElement的不同在于
//可以返回被删除的那个元素,建议使用这个方法
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;
return oldValue;
}
移除方法,如果传入的是一个元素,那就移除vector中从头开始遍历第一次出现的那个元素;如果传入的是一个索引,那么直接移除该索引的元素即可,从上面代码可以看出,移除是通过数组覆盖实现的,即将原数组从需要移除元素的索引开始,每一个元素向前移动一次,再将最后一个元素赋值为null,使其被GC回收即可。
10.其他常用方法
public void clear(){
//清空vector中的元素
removeAllElements();
}
public synchronized boolean equals(Object o){
//比较两个vector是否一样
return super.equals(o);
}
public synchronized int hashCode(){
//获得此vector的hash值
return super.hashCode();
}
public synchronized String toString(){
//转化为字符串,调用父类方法,此方法ArrayList就没有
return super.toString();
}
这些方法也就不一一赘述了,都是比较常见的方法。
从上面这些方法可以明显的看出,Vector的对外方法基本都用synchronized修饰符修饰了,那为什么都需要此修饰符修饰呢?我们先来弄清楚synchronized修饰符有什么用。
synchronized可直译为同步,在java中是用来控制线程同步的,在多线程的情况下保证代码不被同时执行,其主要使用情况有三种:
1.修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
2.修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
3.修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁
即被synchronized修饰的方法相当于在方法进入的地方加了一道门,门上有一把锁,该锁只有一把钥匙,一个线程执行到这个门口处,它就去申请锁的钥匙,钥匙只有一把,如果该方法内已经有了一个线程在运行,那么此线程就进不去了,直到里面的线程执行完毕,出了方法并还了钥匙,那么这个线程才能拿到钥匙开门进去执行,否则就一直在门外等着。
这样的好处就是保证了数据的安全性,但是坏处就是降低了速率,而且一旦很多线程都运行到了门前,那么可能会造成线程阻塞。
自此,我们基本上弄清楚了Vector这个类的基本概念。那么再来分析一下ArrayList和Vector的异同之处。
异同 | ArrayList | Vector |
实现方式 | 利用动态数组实现,底层存储数据的是Array数组。 | 利用动态数组实现,底层存储数据的是Array数组 |
结构框架 | 继承自AbstractList父类,实现了List、RandomAcess、Cloneable、Serializable接口。 | 继承自AbstractList父类,实现了List、RandomAcess、Cloneable、Serializable接口。 |
构造方法 | 三个构造方法,无参、集合数组大小作参数以及新集合作参数,其中无参构造时ArrayList内部是一个空数组。 | 四个构造方法,无参、向量数组大小作参数、向量数组大小和增长系数作参数以及新集合作参数,其中无参构造时Vector内部是一个长度为10的数组。 |
数据操作 | 查询、修改速度快,增加、删除速度慢,主要方法有get、set、add、remove、clear等。 | 查询、修改速度快,增加、删除速度慢,常用方法有get、set、add、remove、clear等。 |
线程安全 | 线程不安全,不适合在多线程下使用,适合于单线程,且效率高。 | 线程安全,适合在多线程下使用,但是效率低。 |
扩容方式 | 每次扩容先判断集合数组是否为空,否则直接初始化为容量为10的数组。若数组不为空,则增加到原数组长度的1.5倍和传入扩容参数比较,取最大值进行扩容。 | 每次扩容先判断是否设置了增长系数,如果设置了就比较原数组长度加增长系数和传入扩容参数,取最大值进行扩容。否则将增加到原数组长度的2倍和传入参数比较,取最大值扩容。 |
参考博客:
https://blog.youkuaiyun.com/yangshiziping/article/details/52550291
https://blog.youkuaiyun.com/qq_37113604/article/details/80836025
https://www.jianshu.com/p/a2236f562ead
https://blog.youkuaiyun.com/u012761326/article/details/83015521
https://blog.youkuaiyun.com/u011419651/article/details/83831156