ArrayList 源码-末尾add方法流程

561 阅读3分钟

ArrayList 源码-末尾add方法流程

arrayllist使用原理 (数组末尾add方法流程) 使用Arraylist时,首先会实例一个arrayList的对象,然后调用其中的add方法来添加元素,进入add的源码中看是这样的: image.png

这个add方法是从数组末尾开始插入元素的, 一开始会有个ensureCapacityinternal方法,里面的参数为size+1,size在最开始的时候size是未定义具体的值,

image.png 所以,此时的size为0, ensureCapacityInternal(size + 1) 的意义就是进行数组长度处理, 下面的操作就是我们正常用数组放元素的操作了,将当前元素放入到当前下标所在的地址,然后下标后移一位.这样就完成了将元素放入数组的操作了,之后返回true,告知调用者此元素已经被放入到数组中了.

进入到ensureCapacityInternal的源码中查看,代码是这样设计的:

image.png 此时传进来的参数为最小的容量大小 此时又调用了ensureExplicitCapacity方法,这个方法中又调用了calculateCapacity这个方法,传入的是elementData和minCapacity两个参数, elementData是提前定义好的,是一个空的对象数组:

image.png 这里的elementData使用的是transient关键字,表示这个数组不会被序列化. 看到这似乎还是不太懂这是要做啥,只能在进入源码查看…

image.png

此时进入的是calculateCapacity方法

image.png 这里有一个if判断,判断elementData是否跟定义的DEFAULTCAPACITY_EMPTY_ELEMENTDATA这个数组相等,如果相等,就会返回DEFAULT_CAPACITY和minCapacity 之间的最大的那个数值回去,这里的DEFAULT_CAPACITY是定义好的,如图所示:

image.png 如果不相等,则返回minCapacity的数值 此时两者是相等的,所以会返回10,

回到原来的ensureCapacityInternal方法,此时方法里面的参数为10, 打开方法的源码查看一下:

image.png

首先会看到的是modCount这个变量,

image.png

这个变量是由proteced的关键字来修饰的,是可以被子类所继承的,然后它初始的值为0; 这个变量放这里有什么作用呢? 它代表该List对象被修改的次数,每对List对象修改一次,modCount都会加1. 通过这个变量来判断List对象是否被修改了,如果被修改了则抛出java.util.ConcurrentModificationException异常。

当传入的minCapacity减去elementData的长度大于0的时候,会调用grow方法 这个逻辑为什么要写在这里呢? 这是一个判断是否会溢出的代码,写在这里可以看出设计者对代码安全的一种判断.

当前的minCapacity为10, elementData为空数组,长度为0,此时为true,进入grow方法中 这时候我们来看看grow的源码

image.png

这里有个扩容机制,当需要扩容的时候,

image.png 这里就会起作用,首先获得elementData 的长度,然后通过右移一位在加上原来的长度,就是新的容器的长度,而我们都知道,往右移一位,就是类似除以2的意思,所以,如果容器需要扩容的话,扩容了一半的长度,而新容器的长度就是原来容器的1.5倍,

接下来会有一个判断如果新容器的长度扩容后还是小于minCapacity,则将minCapacity的值赋给新的容器,如果新的容器长度已经超过了数组的最大长度,则会抛出异常

image.png 这是数组最大长度的定义

如果两个if都不成立,则通过Arrays的copyOf方法,将新数组复制到原来数组中,新的数组的长度就可以容纳放进来的元素了. 之后在通过开头所看到的:

image.png

将新的元素放到数组的末尾,这个add的操作就完成了