可以看到无参构造使用的是DEFAULTCAPACITY_EMPTY_ELEMENTDATA空数组,而使用指定容量的构造方法,当容量为0时,使用的是EMPTY_ELEMENTDATA。
即将无参构造的空数组与指定容量为0的有参构造方法区分开来
共同点是:数组都是空数组
不同点是:数组不是同一个对象
我们来看一下为什么要加这个DefaultCapacity_empty_elementData空数组
注释上说,是为了了解添加第一个元素时要膨胀多少
可以看到add方法与JDK1.7是几乎一样的,步骤都是
检查底层Object数组容量
在底层Object数组对应位置增加值
返回true
接下来,我们看看ensureCapacityInternal与ensureExplicitCapacity是怎么执行的
![在这里插入图片描述](https://www.www.zyiz.net/i/ll/?i=20210604225642166.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
0dEVVRfVHJpbQ==,size_16,color_FFFFFF,t_70#pic_center)
这里是一个与JDK1.7的不同点,我们回顾一下JDK1.7的版本是怎样的
JDK1.7是要先针对第一次的无参构造产生的elementData进行扩容(要设置默认容量为10)
但JDK1.8却没有针对第一次的无参构造产生的空数组进行扩容,但其还调用了另一个方法calculateCapacity来进行计算需要的容量
那接下来就看看,这个方法做了什么
可以看到,这个calculateCapacity方法做的内容跟JDK1.7的ensureCapacityInternal的第一步针对无参构造的判断几乎是一致,JDK1.8只不过将这一步拆分出来放在了calculateCapacity里
然后ensureExplicitCapacity是一致的,都是ensureCapacityInternal最后都要进行调用的方法,判断当前新增所需的容量大于当前的容量,大于就要进行扩容
接下来看看grow方法
跟JDK1.7也是一样的,没有任何变化
默认扩容规则为1.5倍
如果扩容后的容量仍然不够,即仍然小于增加元素所需的容量,那么扩容后的新容量改为增加元素所需的容量
判断扩容后的容量是否大于MAX_ARRAY_SIZE(值为Integer最大值减8)
如果大于,就需要更大的容量,调用hugeCapacity
可以看到,最大值顶多就是Integer的最大值
接下来,我们看看另一个add方法
可以看到,跟JDK1.7的是一样的,连rangeCheckForAdd都是一样的
步骤也是一样的
判断指定index是否合理
判断容量是否足够
使用arrayCopy将底层Object数组向后移一位,腾出index位置出来
将底层Object数组的index位置赋上指定的值
最后让size++
可以看到clear方法也是没变的,跟jdk1.7一摸一样
也是遍历底层Object数组,然后逐个设置为Null,让gc收集不要的引用
跟jdk1.7也是一摸一样的
检查index是否合理
modCount自增,代表底层数组发生变化
使用elementData获取旧的数据
调用arrayCopy方法将底层Object数组向前移一位,空出最后一个位置
让最后一个位置设置为Null,顺便让size自增,代表元素少一个
设置为null,让gc回收不要的引用
也是跟JDK1.7一样,丝毫没有变过
分为null和非null两种情况
null使用双等于号,非null使用equals判断是否相等
遍历底层数组,去进行匹配符合的索引
调用fastRemove去移除匹配的索引
看一下fastRemove方法
也是跟JDK1.7没用,没变的
调用arraycopy去将底层数组指定索引后面的那些元素往前移动一位,然后删除最后一位,将最后一位设为Null,让gc回收不要的引用