vector原理 java_Java集合包(三)——List实现类之ArrayList与Vector原理分析

一:ArrayList特征

ArrayList 是一个 动态数组。与Java中的基本数组相比,它的容量能动态增长。

ArrayList中的操作不是线程安全的,建议在单线程环境下使用。多线程中可以选择JUC并发包中的CopyOnWriteArrayList。

二:ArrayList的继承与实现关系

36c38479d2cfb51695fbf3a7329aafa6.png

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、源码分析

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

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类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值