Java ArrayList扩容问题实例详解
本文研究的主要是JavaArrayList扩容问题实例详解的相关内容,具体介绍如下。
首先我们需要知道ArrayList里面的实质的其实是一个Object类型的数组,ArrayList的扩容问题其实就是这个Object类型的数组的扩容问题。
transientObject[]elementData;
一、创建时,ArrayList的容量分配
创建一个ArrayList有三种情况
1、默认大小创建(默认为0)
ArrayListal=newArrayList();
创建完成之后,al的容量为0。从下面代码就可以知道。
transientObject[]elementData;
privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};
publicArrayList(){
this.elementData=DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
2、指定大小创建
ArrayListal=newArrayList(5);
创建一个容量为5的ArrayList对象,其实就是一个长度为5的Object数组,从下面代码就可以知道。
transientObject[]elementData;
privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};
publicArrayList(intinitialCapacity){
if(initialCapacity>0){
this.elementData=newObject[initialCapacity];
}elseif(initialCapacity==0){
this.elementData=EMPTY_ELEMENTDATA;
}else{
thrownewIllegalArgumentException("IllegalCapacity:"+
initialCapacity);
}
}
3、指定元素集合创建
ArrayListal=newArrayList(Arrays.asList(1,2,3,4,5));
上面创建了ArrayList对象,并使用一个List为[1,2,3,4,5]来进行初始化。其实就是创建了一个长度为5的Object数组,数组的内容为[1,2,3,4,5]。从下面代码就可以知道。
privateintsize;
transientObject[]elementData;
privatestaticfinalObject[]DEFAULTCAPACITY_EMPTY_ELEMENTDATA={};
publicArrayList(Collectionc){
elementData=c.toArray();
if((size=elementData.length)!=0){
//c.toArraymight(incorrectly)notreturnObject[](see6260652)
if(elementData.getClass()!=Object[].class)
elementData=Arrays.copyOf(elementData,size,Object[].class);
}else{
//replacewithemptyarray.
this.elementData=EMPTY_ELEMENTDATA;
}
}
二、插入元素时,ArrayList的容量扩充
ArrayListcollection=newArrayList (Arrays.asList(1,2,3,4,5)); Integer[]moreInts={6,7,8,9,10}; collection.addAll(Arrays.asList(moreInts));
上面过程如下:
1、创建一个size为5的ArrayList,内容为[1,2,3,4,5]。——初始容量为5
2、向这个ArrayList对象里面添加集合{6,7,8,9,10}。——-这个时候,就需要对这个ArrayList对象容量进行扩充了。
查看源码:
publicBooleanaddAll(Collectionc){
//得到插入数组
Object[]a=c.toArray();
//得到插入内容长度
intnumNew=a.length;
ensureCapacityInternal(size+numNew);
//IncrementsmodCount
System.arraycopy(a,0,elementData,size,numNew);
size+=numNew;
returnnumNew!=0;
}
privatevoidensureCapacityInternal(intminCapacity){
//如果ArrayList里面的内容为空
if(elementData==DEFAULTCAPACITY_EMPTY_ELEMENTDATA){
minCapacity=Math.max(DEFAULT_CAPACITY,minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
privatevoidensureExplicitCapacity(intminCapacity){
modCount++;
//进一步计算扩充后的大小minCapacity
if(minCapacity-elementData.length>0)
grow(minCapacity);
}
privatevoidgrow(intminCapacity){
//ArrayList的原始大小
intoldCapacity=elementData.length;
//在原始大小的基础上计算扩充后的大小,扩充后的大小是元素大小的1.5倍
intnewCapacity=oldCapacity+(oldCapacity>>1);
//跟前面计算的扩充后长度minCapacity比较,取较大的那个为扩充后长度
if(newCapacity-minCapacity<0)
newCapacity=minCapacity;
//如果扩充后长度大于最大长度
if(newCapacity-MAX_ARRAY_SIZE>0)
newCapacity=hugeCapacity(minCapacity);
//扩充
elementData=Arrays.copyOf(elementData,newCapacity);
}
privatestaticinthugeCapacity(intminCapacity){
//minCapacity小于0,说明溢出,否则将最大整数作为最终扩充长度
if(minCapacity<0)//overflow
thrownewOutOfMemoryError();
return(minCapacity>MAX_ARRAY_SIZE)?
Integer.MAX_VALUE:
MAX_ARRAY_SIZE;
}
上面的过程可以这样总结:
1、ArrayList的原始大小size+将要插入集合的大小numNew=得到扩充后ArrayList的最小长度minCapacity
2、如果ArrayList的原始大小size为0,即ArrayList为空,ArrayList扩充后的最小长度minCapacity=Math.max(10,minCapacity),也就是说扩充后的最小长度minCapacity,并不仅仅是原始长度size加上插入集合的长度numNew。
3、上面得到的扩充后最小长度minCapacity,并不是最终扩充后的长度,还需要进一步进行计算。
(1)得到ArrayList的原始大小oldCapacity
(2)得到新的扩充后的大小:newCapacity=oldCapacity*1.5;
(3)将上面计算的扩充后的最小长度minCapacity与这里得到的扩充后的大小newCapacity进行比较,取较大的那个最为最终扩充后的大小。
总结
以上就是本文关于ArrayList扩容问题实例详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!