java集合类源码详解-ArrayList(6)-基于JDK8

前面忘了说 博客对于ArrayList的源码剖析 针对的是JDK8

ArrayList的常用方法还没有测试,这次来测试阅读ArrayList的核心方法,当我们添加元素,超过了容器的初始容量底层会发生什么,然后测试这些核心方法。

其实之前已经看过这种情况的源码了,其实就是底层的ensureExplicitCapacity()来判断是否扩容,这个方法翻译成中文意思是:确保精确容量。

这次再复习一下吧。

点击下一步,这里这里容量是2,前面添加的两个元素 不会超出容器的容量,所以下图中的这个逻辑判断是false,

不会执行grow() 扩容函数。这三个add()前两个底层执行过程一模一样,第三个跟前面在ensuerExplicitCapacity()这个函数 只有一处区别 就是if 判断为true 执行了grow()函数,进行扩容,因为此时添加了一个元素,最小容量也得是3,已经超出了初始容量2.

现在直接看第三个add()的底层执行

点击下一步,此时minCapacity是3

再次点击下一步。判断一下,这个容器使用的是不是无参构造。这里肯定没有

再次点击下一步,如果最小容量比容器容量大就开始执行扩容函数

再次点击下一步,这里把旧的底层数据容量2 拿给oldCapacity这个变量

然后这个变量自身加上自身的值右移一位 等于3

然后判断新容量是否小于最小容量

这里都不会执行 直接跳到最后一步,把底层数据扩容到newCapacity。然后弹栈,最后一句add()方法执行结束

这里可以看到add()方法有两个,而且都是重写父类AbstractList的add()方法

这里写上一段,测试程序。add(int index,E element) 这个函数是在一个索引位插入一个元素,这个索引位后面的元素依次往后移。这里我们先猜测一下底层源码,插入元素,应该判断插入位置是否合法以及这个数组的容量还够不够。

学过数据结构的应该知道,数组适合查找,但是如果是增加(插入)或者删除,效率非常低,因为在中间插入一个元素,这个索引位后面的依次往后移动。

点击下一步,开始调试,正如我们所想,一开始判断下标是否越界

我们这里再点下一步,进这个函数看看,这里判断索引index 不能大于size 也不能小于0

也就是说下标不能为负,如果没有元素只能往0号添加,如果有元素只能往这些元素的中间或者最后添加,不能添加到比这些元素的最后还最后,比如这里容量为30. 里面有2个元素,不能添加到索引位3及以后的位置

再点击下一步,这里遇到个非常熟悉的函数ensureCapacityInternal();此时最小容量是3 没有超过容器的容量

所以不会执行ensureapacityInternal()里面的ensureExplicitCapacity()里面的grow()函数

 

点击下一步,会到add()方法,

这里可以看到这里并没有让索引位后面的数依次往后移,而是数组的自拷贝。

从element数据的index位置开始复制 ,复制到element数组的index+1位置开始

而要知道index这个索引位 在这个索引位开始都往后移完成了之后,这个索引位后面有多少元素

就是size-index。

这里执行数组的拷贝后还剩下0号索引,刚好让我们能往这个位置插入元素,然后容器的实际数据大小加1.

 添加还有两个方法addAll(),之后再阅读他的源码,现在先把重要的删除等核心方法看看。

现在开始阅读remove()方法。可以看到这里有5个remove类似的方法。

这里我们就只暂时只测试remove(int index)

点击下一步,remove()这个函数会移除指定位置的元素,并且index之后的元素依次左移一位,如果不补空位

会导致浪费空间

点击下一步,先看索引位是否合法,这个rangecheck()跟之前的不一样,这里index不能等于size,否则就是 删除数组里面最后一个数据的下一位,这显然是不行的,既然是最后一个元素下一位肯定是没有元素的。

 点击下一步,这里执行删除方法会影响数组的数据的数据量大小,所以执行modcount++

点击下一步,这个函数也很熟悉了,传个索引位进去,返回对应索引位的数据

然后把这个返回值赋值给E(这里是Integer)类型的oldValue变量。

再次点击下一步,如果要想知道一个索引位后面有多少个数,那么就是数据的实际长度 - 索引位 - 1

这里得到要移动的长度

然后判断要移动的长度,决定是否调用system.arraycopy(),这里的逻辑判断其实就是如果不是删除的最后一个,就会去自拷贝

 system.arraycopy() 这个函数是JVM底层由c++实现了,这里不好看源码,知道作用就行

然后点击下一步,因为索引位后面的全部往前移一位,所以最后面肯定会空一位

所以把最后一个赋为null,然后直接返回这个被删除的元素

 运行结果

猜你喜欢

转载自blog.csdn.net/qq_37889257/article/details/84391706
今日推荐