ArrayList扩容机制分析~
一、从ArrayList的构造函数说起
1.1、ArrayList有三种方式初始化,构造方法的源码如下:
|
从以上三种构造创建ArrayList对象可知:
以无参构造方法创建ArrayList时,实际上初始化赋值的是一个空数组,真正对数组进行添加元素操作时,才是真正分配容量,即向数组中添加第一个元素时,数组容量扩为10
二、ArrayList扩容机制分析
1、add()
方法
|
2、由add
方法引出ensureCapacityInternal方法
//得到最小容量 |
由此可知,当要add第一个元素时,minCapacity为1,在Math.max()方法比较后,minCapacity为10
3、再引出ensureExplicitCapacity方法
如果调用ensureCapacityInternal()
方法就一定会执行这个方法:
//判断是否需要进行扩容 |
走到这里,可以思考一下:
-
当要执行add方法进行第一个元素的插入时,elementData.length为0(因为是一个空list),
接下来执行
ensureCapacityInternal
方法,使得minCapacity
此时为10,接下来执行ensureExplicitCapacity
方法,那么minCapacity - elementData.length > 0
成立,所以会进入
grow(minCapacity)
扩容方法; -
当add插入第二个元素时,minCapacity为2,此时
elementData.length
(容量)在添加第一个元素之后扩容为10,那么minCapacity - elementData.length > 0
不成立,因此不会进入grow
扩容方法; -
直到添加第11个元素时,
minCapacity
为11比当前的容量10要大,进入grow方法进行扩容;
4、grow
扩容方法
|
int newCapacity = oldCapacity + (oldCapacity >> 1),所以 ArrayList 每次扩容之后容量都会变为原来的 1.5 倍!
4.1、grow
方法的分析
- 当add方法插入第一个元素时,oldCapacity为0,经过第一个if判断成立后,newCapacity = minCapacity为10,但是第二个if判断不成立,即newCapacity不会比MAX_ARRAYS_SIZE大,则不会进入
hugeCapacity
方法。数组容量为10,add方法中 return true,size增为1。 - 当add第十一个元素时进入grow方法时,newCapacity为15,比minCapacity(11)大,第一个if判断不成立,新容量没有大于数组的最大size,也不会进入hugeCapacity方法,数组容量扩容,仅此而已,add方法之后,return true,size增为11;
- 以此类推。。。
5、hugeCapacity()
方法
从上面 grow()
方法源码我们知道: 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) hugeCapacity()
方法来比较 minCapacity 和 MAX_ARRAY_SIZE,如果minCapacity大于最大容量,则新容量则为Integer.MAX_VALUE
,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 Integer.MAX_VALUE - 8
。
private static int hugeCapacity(int minCapacity) { |
三、System.arraycopy()
和Arrays.copyOf()
方法
ArrayList中大量调用了这两个方法,扩容操作以及add(int index,E element)
、toArray
等方法中都用到了该方法
3.1、System.arraycopy()
方法
|
Arrays.copyOf()
方法
|
使用 Arrays.copyOf()
方法主要是为了给原有数组扩容
3.3、两者之间的区别和联系
联系
copyOf()
内部实际调用了 System.arraycopy()
方法;
区别
arraycopy()
需要目标数组,将原数组拷贝到你自己定义的数组里或者原数组,而且可以选择拷贝的起点和长度以及放入新数组中的位置 ;
copyOf()
是系统自动在内部新建一个数组,并返回该数组。
近期评论