Java面试必备:从源码角度看 ArrayList扩容机制

很多Java程序员在面试中都会碰到一些槛,让得很多人比较为难。尤其是一些类似于数据机制类的东西,有很多人根本不懂。今天,笔者就来分享下ArrayList的扩容机制。

​首先从 ArrayList 的构造函数说起:ArrayList有三种方式来初始化,构造方法源码如下:

由于篇幅原因,笔者放的是代码的截图。但是看看这段代码,细心的同学可能已经发现了 ,用无参数构造方法创建 ArrayList 的时候,初始化赋值的实际上是个空数组。当为这个数组添加元素的时候,才开始分配容量。即向数组中添加第一个元素时,数组容量扩为10。 下面在我们分析 ArrayList 扩容时会降到这一点内容!以这个为例子分析,首先看看add方法:

再来看看 ensureCapacityInternal()方法和ensureCapacity()方法:

可以看到,add方法首先调用了ensureCapacityInternal(size + 1),当 要 add 进第1个元素时,minCapacity为1,在Math.max()方法比较后,minCapacity 为10。当我们要 add 进第1个元素到 ArrayList 时,elementData.length 为0 (因为还是一个空的 list),因为执行了 ensureCapacityInternal()方法 ,所以 minCapacity 此时为10。此时minCapacity - elementData.length > 0成立,所以会进入 grow(minCapacity)方法。

当add第2个元素时,minCapacity 为2,此时e lementData.length(容量)在添加第一个元素后扩容成 10 了。此时,minCapacity - elementData.length > 0不成立,所以不会进入 (执行)grow(minCapacity)方法。添加第3、4···到第10个元素时,依然不会执行grow方法,数组容量都为10。直到添加第11个元素,minCapacity(为11)比elementData.length(为10)要大。进入grow方法进行扩容。

再看看grow方法

int newCapacity = oldCapacity + (oldCapacity >> 1),所以 ArrayList 每次扩容之后容量都会变为原来的 1.5 倍! 再来看看hugeCapacity()方法。

​从上面 grow()方法源码我们知道: 如果新容量大于 MAX_ARRAY_SIZE,进入(执行) hugeCapacity()方法来比较 minCapacity 和 MAX_ARRAY_SIZE,如果minCapacity大于最大容量,则新容量则为Integer.MAX_VALUE,否则,新容量大小则为 MAX_ARRAY_SIZE 即为 Integer.MAX_VALUE - 8。ArrayList 源码中有一个 ensureCapacity方法不知道大家注意到没有,这个方法 ArrayList 内部没有被调用过,所以很显然是提供给用户调用的,那么这个方法有什么作用呢?

可以看到,最好在 add 大量元素之前用 ensureCapacity方法,以减少增量从新分配的次数。而通过如下代码即可达到使用效果。

运行结果:使用ensureCapacity方法前:4637,使用ensureCapacity方法前:241。通过运行结果,我们可以很明显的看出向 ArrayList 添加大量元素之前最好先使用ensureCapacity方法,以减少增量从新分配的次数。

发表评论
留言与评论(共有 0 条评论)
   
验证码:

相关文章

推荐文章

'); })();