1.4ArrayList源码解析
1.4.1.无参构造器创建ArrayList
1.首先创建一个ArrayList,并采用无参构造器进行初始化对象。
当我们在第12行打一个断点追溯进去,无参构造器当中的代码为:this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA
向上翻阅源码,会发现其实ArrayList底层就是一个Object类型的数组elementData,来存放我们add进去的元素,而DEFAULTCAPACITY_EMPTY_ELEMENTDATA 就是一个空数组,当我们使用无参构造器创建ArrayList对象的时候,就会初始化elementData为空的数组。
2.执行list.add(“a”),我们一起追溯进去看看ArrayList到底是怎么样进行大小扩容的。
当执行list.add()方法的时候,发现会执行ensureCapacityInternal 方法,并且传入的参数为size+1,size表示的是ArrayList的长度,刚开始的size值为0,为了能让他执行当前的add方法,则需要给他先加上一个长度,才能添加当前的这个元素。
接着我们继续step into ensureCapacityInternal 这个方法,接着step into calculateCapacity() 方法,calculateCapacity方法传入的参数为数组以及当前所需最小容量。
进入到方法以后,会先坐一个判断,如果当前elementData数组为null,则返回DEFAULT_CAPACITY(10)和 minCapacity当中的最大值,则也说明了当我们使用无参构造器创建ArrayList对象的时候,第一次扩容的大小为10,默认我们第一次就需要10个大小。
接着退出calculateCapacity() 方法,进入ensureExplicitCapacity() 方法,有一个modCount变量记录着我们对list集合进行了几次操作。接着会执行第238行的if语句,我们的minCapacity为刚刚方法的返回值10,而elementData.length为0,所以会执行grow()方法。
接着step into grow()方法,这个方法也可以算是扩容的核心算法了,首先将当前数组的长度赋值给oldCapacity,接着执行259行,将1.5倍的旧容量赋值给新的容量,这也就是我们所知道的ArrayList第二次进行扩容的时候,是第一次的1.5倍大小。
但其实当第一次进入grow() 方法的时候,old和new都为0,所以260行的if语句为true,会把第一次扩容的10赋给newCapacity
接着再执行第265行Arrays.copy() ,将原本的elementData 复制赋值回去,通过debug可以看出此时的elementData数组为10个null值。
接着会继续执行add方法剩下的语句,也就是将元素添加进数组当中。
此时list集合当中已经有一个a,这个时候程序会继续执行add(b)。
后面就是重复的步骤,当list添加了10个元素以后,就会继续扩容,将newCapacity赋值为oldCapacity的1.5倍,也就是第二次扩容会有15个空间。这边就不再继续演示源码过程,直接贴上添加第十一个元素的时候,list集合的情况。
1.4.2.有参构造器创建ArrayList
上面演示的是通过无参构造器进行集合的创建。还有另一种方法,就是通过有参构造器来指定capacity的初始化大小
1.初始化大小为15
2.调用有参构造器,通过源码就可以看出在第153行,就直接把数组的长度设置为我们传进去的值。接着后面扩容的步骤也是oldCapacity的1.5倍
1.4.3有参构造和无参构造总结
- 如果是有参构造器,初始大小为传入的容量。往后的每次扩容都为原来的1.5倍
- 如果是无参构造器,第一次扩容大小为10。往后的每次扩容都为原来的1.5倍
|