ArrayList源码分析

咱们主要分析一下,实例化的过程和数组扩容的过程。

为什么要看这个呢,这几天面试的时候,发现很多面试的人并不知道初始化数组长度是多少,每次扩容是多少,所以我也抱着怀疑的态度,自己看一下ArrayList的源码。

首先我看看一下自己的JDK的版本信息

在提前准备好例子,可以更好的看源码。

1.实例化的过程

直接进去ArrayList()的方法里面,可以看到下面的这个图。

这里我们就发现我们如果使用默认的实例化方式的话,其实数组里面是个空数组的。

还有一个是带Integer的初始化方式,源码看下面。

这个看起来就比较简单了,如果实例化的initialCapacity值大于0,那么初始化数组长度就是initialCapacity。如果initialCapacity是空,声明出来的还是一个空数组。如果小于0,就直接抛出异常就可以了。

当然了,初始化的方式不至这两种,还有参数是Collection的方式,这种大家自己看看就好了,很好理解的。

2.ArrayList是怎么添加数据的

直接进入add方法,看看里面是怎么写的就好了。

第一次看到这个,我就很懵逼,我说这个是个什么东西呢?

elementData[size++] = e;这个肯定是个复制操作的。

那么ensureCapacityInternal(size + 1);这个里面就是有扩容的操作的。

进入到ensureCapacityInternal的方法里面看看是怎么个扩容的。

都是一些看不懂的英文,自己也不知道这个里面的两个方法是做了什么,然后先去calculateCapacity里面看看他的逻辑是什么

这个里面的minCapacity就是size+1,也就是数组长度+1,默认情况下size+1就是1,calculateCapacity返回值就是10了。

继续跟下一个函数ensureExplicitCapacity,参数是个Integer,我们再来看看这个函数里面做了什么操作吧。

modCount是什么呢?按字面里面就是修改的次数,是ArrayList的一个成员变量。

在下面就是判断一个minCapacity和数组长度大小谁大,如果minCapacity大,就执行grow函数,这个行数也就是扩容的核心函数了。如果数组大,就不做任何操作。

下面继续看看grow里面,都做了什么吧,直接上图,看源码。

int newCapacity = oldCapacity + (oldCapacity >> 1);直接就找到了扩容多大的方法,这才知道,扩容的时候是进行了位操作的。

虽然知道了每次是怎么扩容的,但是并不知道每次都是这么扩容的,看一下下面的两个if判断的逻辑又是什么呢?

如果newCapacity比minCapacity小,就newCapacity就用minCapacity,正常情况下,如果数组长度大于2的情况,一般都是大于minCapacity的。

就下来就是比较newCapacity和MAX_ARRAY_SIZE的大小了。

我们看一下MAX_ARRAY_SIZE是Integer.MAX_VALUE - 8,如果newCapacity比MAX_ARRAY_SIZE大,那么就需要看一下hugeCapacity里面的方法了。

return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;

这段就很好理解了,如果超过MAX_ARRAY_SIZE就是Integer.MAX_VALUE,如果没有最后就是MAX_ARRAY_SIZE。

所以这里扩容的时候最大的数组大小就是Integer.MAX_VALUE,也就是2 的 31 次方 - 1 = 2147483648 - 1 = 2147483647。

3.疑问

ArrayList有没有缩容的情况呢?这个就大家找一下源码就知道了,我也找了一下remove的源码,这个大家也可以动手去看一下。

clear的时候,数组大小会不会表呢?

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值