ArrayList小结

首先ArrayList是我们List接口的一个实现类,是线性非安全的。优点是访问数据快,复杂度为O(1),缺点是对数据进行删除和添加的话不方便,时间复杂度在最好的情况下为O(1),最坏的情况下为O(n)。 那么接下来我们就来看看ArrayList在jdk中是如何实现的:

java list自动扩容机制_ci

第一个参数是10,是ArrayList在加入元素时会进行,扩容的长度。然后是两个默认的空数组。接下来我们就可以来看一下ArrayList的初始化,以及它是如何进行元素的添加和扩容的。

java list自动扩容机制_数组_02


首先是两个构造方法,分别是带参数的构造方法和不带参数的构造方法。我们可以看到,如果我们在构造ArrayList的时候如果一开始就带了参数那么如果参数大于0的情况下我们会为它创建长度为参数大小的数组,否则我们按照默认的空数组进行创建。

java list自动扩容机制_ci_03


来到add方法,首先我们将size进行一个加一,因为我们我们是新加入了一个元素,然后调用我们的ensureCapacityInternal方法判断我们现在的存储空间是否是够用的,然后我们进行一个赋值操作。

java list自动扩容机制_ci_04


在这里我们可以看到我们将现在的size和我们的初始默认参数进行了一个比较,并且取了他们当中的最大值。(即当我们加入1个元素时,此时的minCapacity为1,而Default参数为10)

所以此时我们的minCapacity已经变成了10,然后我们进入到ensureExplicitCapacity方法中进行判断。

java list自动扩容机制_构造方法_05


我们可以轻松地看出我们的if是成立的,因为minCapacity是10,而此时的elementData的长度是0.所以我们可以继续向下进入到,grow方法中进行扩容。

java list自动扩容机制_数组_06


在这个方法中我们可以看到我们的ArrayList是怎样进行扩容的了,首先我们将长度定义为之前的长度加上之前的长度右移两位之后得到的树(并不是完全意义上的1.5倍,但是近似)。然后我们判断当前扩容之后的长度是否够用,否则我们就以传入的长度(我的理解此时数据的多少)作为数组长度,因为这是我们一开始取了max之后的长度。例如在addAll() 方法中我们可以看出

java list自动扩容机制_构造方法_07


此时的size是加上了我们要加入的所有元素的长度的。所以我们在前面得到的size+1则是我们此时数据的真实长度,所以我们如果使用此方法,我们的扩容就可能跟不上我们的1.5倍扩容机制,所以我们才有了不够的情况下使用真实长度作为数组长度的情况。而最后的实现才用的是Arrays.copyOf方法,此方法区别于下面的System.arraycopy的方式,此方法是在原数组的基础上进行长度的改变,如一开始我们的数组nums1,2,3 如果我们使用了Arrays.copyOf(nums,5) 此时数组则变为了1,2,3,0,0

ArrayList中还有在index添加元素的add方法,此时我们主要利用的是System.arraycopy的方式进行实现,此方法主要是在两个数组上进行实现,方法的参数分别是源数组,开始复制的下标,目标数组,开始的下标,要复制的长度最后的结果是存在目标数组当中的

类似的实现方式还有remove操作

java list自动扩容机制_java list自动扩容机制_08


以上就是对ArrayList的一些思考总结,欢迎批评指正。