一:ArrayList特征
ArrayList 是一个 动态数组。与Java中的基本数组相比,它的容量能动态增长。
ArrayList中的操作不是线程安全的,建议在单线程环境下使用。多线程中可以选择JUC并发包中的CopyOnWriteArrayList。
二:ArrayList的继承与实现关系
1、继承层次
java.lang.Object
↳ java.util.AbstractCollection↳ java.util.AbstractList↳ java.util.ArrayList
2、类定义与实现
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable {}
1)ArrayList 继承了AbstractList抽象类,并实现了List接口。因此它可以提供相关的添加、删除、修改、遍历等功能。
2)ArrayList 实现了RandmoAccess接口,提供了快速随机访问的功能。
3)ArrayList 实现了Cloneable接口,覆盖了clone()方法,因此可以被克隆。
4)ArrayList 实现java.io.Serializable接口,支持序列化。
三:ArrayList原理
ArrayList中包含两个重要的成员:elementData数组 和 size变量。
1)elementData 数组是"Object[]类型的数组",它保存了添加到ArrayList中的元素:此处涉及泛型擦除的知识,请移步相关博文或自行百度。
elementData是个动态数组,我们能通过构造函数 ArrayList(int initialCapacity)来执行它的初始容量为initialCapacity;如果通过不含参数的构造函数ArrayList()来创建ArrayList,则elementData的容量默认是10。
elementData数组的大小会根据ArrayList容量的增长而动态的增长:当ArrayList容量不足以容纳全部元素时,ArrayList会重新设置容量:新的容量=“(原始容量x3)/2 + 1”。
2) size 则是动态数组的实际大小。
3)ArrayList重写了clone()方法,将全部元素克隆到一个新数组中并设置为elementData成员的引用。
4) ArrayList的序列化与反序列化的方式:序列化时,先写入“容量”,再依次写入“每一个元素”;反序列化时,先读取“容量”,再依次读取“每一个元素”。
四:ArrayList的关键方法
1、数组容量检查并扩容
50 //确定ArrarList的容量。
51 //若ArrayList的容量不足以容纳当前的全部元素,设置 新的容量=“(原始容量x3)/2 + 1”
52 public void ensureCapacity(intminCapacity) {53 //将“修改统计数”+1
54 modCount++;55 int oldCapacity =elementData.length;56 //若当前容量不足以容纳当前的元素个数,设置 新的容量=“(原始容量x3)/2 + 1”
57 if (minCapacity >oldCapacity) {58 Object oldData[] =elementData;59 int newCapacity = (oldCapacity * 3)/2 + 1;60 if (newCapacity
该方法在add方法中被调用:
//添加元素e
67 public booleanadd(E e) {68 //确定ArrayList的容量大小
69 ensureCapacity(size + 1); //Increments modCount!!
70 //添加e到ArrayList中
71 elementData[size++] =e;72 return true;73 }
确保添加元素前,数组的容量足够。
2、迭代与内容访问
(1) 快速随机访问,通过索引值访问内容。
由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素。
list.get(i)
(2) 通过迭代器遍历
Iterator iter =list.iterator();while(iter.hasNext()) {
value=(Integer)iter.next();
}
(03) for循环遍历
for(Integer integ:list) {
value=integ;
}
效率对比:快速随机访问>for循环遍历>迭代器遍历。
原因:快速随机访问可以直接找到元素,for循环遍历复用了快速随机访问机制因此比较快,迭代器需要从头开始迭代并且有hashNext()等相关操作因此比较慢。
3、数组转换
有时我们需要将ArrayList转换回Java基本数组,此时需要调用toArray方法。
ArrayList中对toArray方法进行了重载,分别有以下两种实现:
1)Object[] toArray()
//返回ArrayList的Object数组
134 publicObject[] toArray() {135 returnArrays.copyOf(elementData, size);136 }
该方法直接将ArrayList中的elementData数组内容拷贝一份并返回,由于类型擦除的原因,该数组存储的是Object对象,因此返回的是Object数组。
需要注意:此时在调用处只能用Object[] x 变量来接收返回值,如果用其他类型数组强制接收会出行类型转换异常,因为不能直接将Object类型转换为基本类型。
2) T[] toArray(T[] a)
//返回ArrayList的模板数组。所谓模板数组,即可以将T设为任意的数据类型
139 public T[] toArray(T[] a) {140 //若数组a的大小 < ArrayList的元素个数;
141 //则新建一个T[]数组,数组大小是“ArrayList的元素个数”,并将“ArrayList”全部拷贝到新数组中
142 if (a.length
145 //若数组a的大小 >= ArrayList的元素个数;
146 //则将ArrayList的全部元素都拷贝到数组a中。
147 System.arraycopy(elementData, 0, a, 0, size);148 if (a.length >size)149 a[size] = null;150 returna;151 }
该方法需要传入一个模板数组作为参数,用来承载ArrayList数组中的内容,并返回接受拷贝后该参数的引用。
在此方法中,ArrayList中的数组内容拷贝到容器数组时,会按照传进来的模板参数数组的实际类型来进行转换,然后再复制进模板数组中。
调用示例:
Integer[] newArray = (Integer[])arrayList.toArray(new Integer[n]);//参数为一个某确定长度的确定类型的基本数组
五:Vector【已过时】
1、特征
Vector是一个动态数组,但是它是线程安全的。
Vector元素的访问,使用索引的随机访问方式最快,使用迭代器最慢。
Vector通过为方法加synchronized来实现线程安全。
2、原理
Vector的数据结构和ArrayList差不多,它包含了3个成员变量:elementData数组 , elementCount, capacityIncrement。
(01) elementData 是"Object[]类型的数组",它保存了添加到Vector中的元素。
elementData是个动态数组,如果初始化Vector时,没指定动态数组的>大小,则使用默认大小10。
随着Vector中元素的增加,Vector的容量也会动态增长,若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍。
(02) elementCount 是动态数组的实际大小。
(03) capacityIncrement 是动态数组的增长系数。如果在创建Vector时,指定了capacityIncrement的大小;则,每次当Vector中动态数组容量增加时>,增加的大小都是capacityIncrement。
3、源码分析
packagejava.util;public class Vector
extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
{//保存Vector中数据的数组
protectedObject[] elementData;//实际数据的数量
protected intelementCount;//容量增长系数
protected intcapacityIncrement;//Vector的序列版本号
private static final long serialVersionUID = -2767605614048989439L;//Vector构造函数。默认容量是10。
publicVector() {this(10);
}//指定Vector容量大小的构造函数
public Vector(intinitialCapacity) {this(initialCapacity, 0);
}//指定Vector"容量大小"和"增长系数"的构造函数
public Vector(int initialCapacity, intcapacityIncrement) {super();if (initialCapacity < 0)throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);//新建一个数组,数组容量是initialCapacity
this.elementData = newObject[initialCapacity];//设置容量增长系数
this.capacityIncrement =capacityIncrement;
}//指定集合的Vector构造函数。
public Vector(Collection extends E>c) {//获取“集合(c)”的数组,并将其赋值给elementData
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);
}//将数组Vector的全部元素都拷贝到数组anArray中
public synchronized voidcopyInto(Object[] anArray) {
System.arraycopy(elementData,0, anArray, 0, elementCount);
}//将当前容量值设为 =实际元素个数
public synchronized voidtrimToSize() {
modCount++;int oldCapacity =elementData.length;if (elementCount
elementData=Arrays.copyOf(elementData, elementCount);
}
}//确认“Vector容量”的帮助函数
private void ensureCapacityHelper(intminCapacity) {int oldCapacity =elementData.length;//当Vector的容量不足以容纳当前的全部元素,增加容量大小。//若 容量增量系数>0(即capacityIncrement>0),则将容量增大当capacityIncrement//否则,将容量增大一倍。
if (minCapacity >oldCapacity) {
Object[] oldData=elementData;int newCapacity = (capacityIncrement > 0) ?(oldCapacity+ capacityIncrement) : (oldCapacity * 2);if (newCapacity
newCapacity=minCapacity;
}
elementData=Arrays.copyOf(elementData, newCapacity);
}
}//确定Vector的容量。
public synchronized void ensureCapacity(intminCapacity) {//将Vector的改变统计数+1
modCount++;
ensureCapacityHelper(minCapacity);
}//设置容量值为 newSize
public synchronized void setSize(intnewSize) {
modCount++;if (newSize >elementCount) {//若 "newSize 大于 Vector容量",则调整Vector的大小。
ensureCapacityHelper(newSize);
}else{//若 "newSize 小于/等于 Vector容量",则将newSize位置开始的元素都设置为null
for (int i = newSize ; i < elementCount ; i++) {
elementData[i]= null;
}
}
elementCount=newSize;
}//返回“Vector的总的容量”
public synchronized intcapacity() {returnelementData.length;
}//返回“Vector的实际大小”,即Vector中元素个数
public synchronized intsize() {returnelementCount;
}//判断Vector是否为空
public synchronized booleanisEmpty() {return elementCount == 0;
}//返回“Vector中全部元素对应的Enumeration”
public Enumerationelements() {//通过匿名类实现Enumeration
return new Enumeration() {int count = 0;//是否存在下一个元素
public booleanhasMoreElements() {return count
}//获取下一个元素
publicE nextElement() {synchronized (Vector.this) {if (count
}
}throw new NoSuchElementException("Vector Enumeration");
}
};
}//返回Vector中是否包含对象(o)
public booleancontains(Object o) {return indexOf(o, 0) >= 0;
}//从index位置开始向后查找元素(o)。//若找到,则返回元素的索引值;否则,返回-1
public synchronized int indexOf(Object o, intindex) {if (o == null) {//若查找元素为null,则正向找出null元素,并返回它对应的序号
for (int i = index ; i < elementCount ; i++)if (elementData[i]==null)returni;
}else{//若查找元素不为null,则正向找出该元素,并返回它对应的序号
for (int i = index ; i < elementCount ; i++)if(o.equals(elementData[i]))returni;
}return -1;
}//查找并返回元素(o)在Vector中的索引值
public intindexOf(Object o) {return indexOf(o, 0);
}//从后向前查找元素(o)。并返回元素的索引
public synchronized intlastIndexOf(Object o) {return lastIndexOf(o, elementCount-1);
}//从后向前查找元素(o)。开始位置是从前向后的第index个数;//若找到,则返回元素的“索引值”;否则,返回-1。
public synchronized int lastIndexOf(Object o, intindex) {if (index >=elementCount)throw new IndexOutOfBoundsException(index + " >= "+elementCount);if (o == null) {//若查找元素为null,则反向找出null元素,并返回它对应的序号
for (int i = index; i >= 0; i--)if (elementData[i]==null)returni;
}else{//若查找元素不为null,则反向找出该元素,并返回它对应的序号
for (int i = index; i >= 0; i--)if(o.equals(elementData[i]))returni;
}return -1;
}//返回Vector中index位置的元素。//若index月结,则抛出异常
public synchronized E elementAt(intindex) {if (index >=elementCount) {throw new ArrayIndexOutOfBoundsException(index + " >= " +elementCount);
}return(E)elementData[index];
}//获取Vector中的第一个元素。//若失败,则抛出异常!
public synchronizedE firstElement() {if (elementCount == 0) {throw newNoSuchElementException();
}return (E)elementData[0];
}//获取Vector中的最后一个元素。//若失败,则抛出异常!
public synchronizedE lastElement() {if (elementCount == 0) {throw newNoSuchElementException();
}return (E)elementData[elementCount - 1];
}//设置index位置的元素值为obj
public synchronized void setElementAt(E obj, intindex) {if (index >=elementCount) {throw new ArrayIndexOutOfBoundsException(index + " >= " +elementCount);
}
elementData[index]=obj;
}//删除index位置的元素
public synchronized void removeElementAt(intindex) {
modCount++;if (index >=elementCount) {throw new ArrayIndexOutOfBoundsException(index + " >= " +elementCount);
}else if (index < 0) {throw newArrayIndexOutOfBoundsException(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)
public synchronized void insertElementAt(E obj, intindex) {
modCount++;if (index >elementCount) {throw newArrayIndexOutOfBoundsException(index+ " > " +elementCount);
}
ensureCapacityHelper(elementCount+ 1);
System.arraycopy(elementData, index, elementData, index+ 1, elementCount -index);
elementData[index]=obj;
elementCount++;
}//将“元素obj”添加到Vector末尾
public synchronized voidaddElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount+ 1);
elementData[elementCount++] =obj;
}//在Vector中查找并删除元素obj。//成功的话,返回true;否则,返回false。
public synchronized booleanremoveElement(Object obj) {
modCount++;int i =indexOf(obj);if (i >= 0) {
removeElementAt(i);return true;
}return false;
}//删除Vector中的全部元素
public synchronized voidremoveAllElements() {
modCount++;//将Vector中的全部元素设为null
for (int i = 0; i < elementCount; i++)
elementData[i]= null;
elementCount= 0;
}//克隆函数
public synchronizedObject clone() {try{
Vector v = (Vector) super.clone();//将当前Vector的全部元素拷贝到v中
v.elementData =Arrays.copyOf(elementData, elementCount);
v.modCount= 0;returnv;
}catch(CloneNotSupportedException e) {//this shouldn't happen, since we are Cloneable
throw newInternalError();
}
}//返回Object数组
public synchronizedObject[] toArray() {returnArrays.copyOf(elementData, elementCount);
}//返回Vector的模板数组。所谓模板数组,即可以将T设为任意的数据类型
public synchronized T[] toArray(T[] a) {//若数组a的大小 < Vector的元素个数;//则新建一个T[]数组,数组大小是“Vector的元素个数”,并将“Vector”全部拷贝到新数组中
if (a.length = Vector的元素个数;//则将Vector的全部元素都拷贝到数组a中。
System.arraycopy(elementData, 0, a, 0, elementCount);if (a.length >elementCount)
a[elementCount]= null;returna;
}//获取index位置的元素
public synchronized E get(intindex) {if (index >=elementCount)throw newArrayIndexOutOfBoundsException(index);return(E)elementData[index];
}//设置index位置的值为element。并返回index位置的原始值
public synchronized E set(intindex, E element) {if (index >=elementCount)throw newArrayIndexOutOfBoundsException(index);
Object oldValue=elementData[index];
elementData[index]=element;return(E)oldValue;
}//将“元素e”添加到Vector最后。
public synchronized booleanadd(E e) {
modCount++;
ensureCapacityHelper(elementCount+ 1);
elementData[elementCount++] =e;return true;
}//删除Vector中的元素o
public booleanremove(Object o) {returnremoveElement(o);
}//在index位置添加元素element
public void add(intindex, E element) {
insertElementAt(element, index);
}//删除index位置的元素,并返回index位置的原始值
public synchronized E remove(intindex) {
modCount++;if (index >=elementCount)throw newArrayIndexOutOfBoundsException(index);
Object 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(E)oldValue;
}//清空Vector
public voidclear() {
removeAllElements();
}//返回Vector是否包含集合c
public synchronized boolean containsAll(Collection>c) {return super.containsAll(c);
}//将集合c添加到Vector中
public synchronized boolean addAll(Collection extends E>c) {
modCount++;
Object[] a=c.toArray();int numNew =a.length;
ensureCapacityHelper(elementCount+numNew);//将集合c的全部元素拷贝到数组elementData中
System.arraycopy(a, 0, elementData, elementCount, numNew);
elementCount+=numNew;return numNew != 0;
}//删除集合c的全部元素
public synchronized boolean removeAll(Collection>c) {return super.removeAll(c);
}//删除“非集合c中的元素”
public synchronized boolean retainAll(Collection>c) {return super.retainAll(c);
}//从index位置开始,将集合c添加到Vector中
public synchronized boolean addAll(int index, Collection extends E>c) {
modCount++;if (index < 0 || index >elementCount)throw newArrayIndexOutOfBoundsException(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 booleanequals(Object o) {return super.equals(o);
}//计算哈希值
public synchronized inthashCode() {return super.hashCode();
}//调用父类的toString()
public synchronizedString toString() {return super.toString();
}//获取Vector中fromIndex(包括)到toIndex(不包括)的子集
public synchronized List subList(int fromIndex, inttoIndex) {return Collections.synchronizedList(super.subList(fromIndex, toIndex), this);
}//删除Vector中fromIndex到toIndex的元素
protected synchronized void removeRange(int fromIndex, inttoIndex) {
modCount++;int numMoved = elementCount -toIndex;
System.arraycopy(elementData, toIndex, elementData, fromIndex,
numMoved);//Let gc do its work
int newElementCount = elementCount - (toIndex-fromIndex);while (elementCount !=newElementCount)
elementData[--elementCount] = null;
}//java.io.Serializable的写入函数
private synchronized voidwriteObject(java.io.ObjectOutputStream s)throwsjava.io.IOException {
s.defaultWriteObject();
}
}
View Code
根据源码可以发现:Vector的底层数据结构和操作api大多与ArrayList一致,不同的地方在于:很多API都使用了 synchronized 关键字来保证线程安全。
也正是因为如此,所以Vector在多线程环境下效率比较慢,特别是查询操作也要被锁住,这很不友好。
因此,不推荐使用Vector,而是使用CopyOnWriteArrayList类。