Debug ArrayList 源码

1,ArrayList面试必问
说说ArrayList和LinkedList的区别?
ArrayList默认初始容量为多少?按照几倍来扩容?
说说数组扩容的原理?
说说ArrayList常见方法的时间复杂度?
ArrayList和vector的区别
2,Debug ArrayList源码
由于1.7和1.8几乎没什么变化,本文以jdk1.8为例。
2.1 用Debug分析一个元素是如何add进ArrayList
编写测试用例,打上断点:

先分析构造函数如何初始化,关键步骤如下:

elementData是ArraList底层数组的实现,(ps:hashMap数组使用table命名)

DEFAULTCAPACITY_EMPTY_ELEMENTDATA表示默认的空数组,也就是说ArrayList在构造函数初始化时并不会进行底层数组的初始化。

给元素的添加打上断点,分析过程:

进入add方法内部:
进入ensureCapacityInternal方法内部:此时elementData为空,size+1=minCapacity=1

计算容量,calculateCapacity方法:
DEFAULT_CAPACITY默认容量为10:

继续分析,进入:
核心扩容函数grow:(ps:HashMap中扩容函数为resize)
数组复制Arrays.copyOf:


2.2 用Debug分析如何通过数组下标获取ArrayList元素
打上断点,debug:

首先进行范围检查,而后返回元素


2.3 用Debug分析如何通过数组下标删除一个元素
打上断点:

进入remove方法内部,
2.4 用Debug分析如何通过对象删除一个元素

进入remove方法:
进入fastRemove方法:
2.5 用Debug分析向数组中间添加元素

进入add方法
关于System.arraycopy时间复杂度问题,在添加或者删除最后一个元素的时候不会触发数组的复制机制,时间复杂度为O(1),若是添加到数组中间,由于会触发数组的复制,时间复杂度为O(n)。对于删除元素同样,根据数组下标删除的情况下,删除尾部元素是不会触发数组的扩容机制的,若删除中间的元素,同样会触发数组的复制。若根据对象删除元素,由于本身遍历到对象的时间复杂度为O(n),删除元素后再对数组进行重组,所以时间复杂度为O(n^2)。
版权声明: 本文为 InfoQ 作者【Noneplus】的原创文章。
原文链接:【http://xie.infoq.cn/article/0f84fd17e4e72a247431d40c1】。文章转载请联系作者。
评论