ArrayList手写前的源码整理
简单说明下:ArrayList是一个数组队列,相当于动态数组,与java中的数组相比能动态增长。
特点:
1.随机访问速度快,插入和移除性能较差
2.支持null
3.有顺序
4.元素可以重复
5.线程不安全
想要手写一个ArrayList必须了解他的底层逻辑,我把我的理解整理的下
首先看看源码
(以下为1.8环境的源码)
首先这里可以看到有两个空数组,先来看一下这两个空数组的区别
从两个构造函数可以看到无参构造将内置数组指向了长空数组,当传入参数为0时将内置数组指向了短空数组。
下面用代码看一下区别,这里用反射查看了内置数组的长度
当添加一个元素后
可以看到无参构造指向的长空数组长度变为了10,而短空数组变为了1,既然是在add操作之后发生了变化,那么就去看看add的源码吧。
这有个属性为modCount
他是在父级AbstractList中声明的,通过注释可以知道这个参数是修改次数标识
接着看代码,
可以看到grow是将内置数组扩容的操作,首先扩容为原大小的1.5倍取整
而后可以看到若是无参构造指向的长空数组,便扩容至10
jdk1.6的构造函数如下,可以看到直接初始化为长度10的空数组
而1.8是添加第一个元素是才将大小扩充至10。
而后又做了一步判断,数组的最大长度为Integer的最大值-8
由注释可以看到这是为了防止机器内存溢出
另外也防止了int形溢出变为负数的情况
a-b>0不等价于a>b
a=Integer.MAX_VALUE+10
b=Integer.MAX_VALUE-10
a-b>0—>true
a>b—>false
看完add再看看其他
Get方法,首先判断下标是否越界,然后将该下标的数组元素返回
set方法,首先判断下标是否越界,然后将原元素返回,新元素替换(set操作并没有使modCount++)
由此可以看到带下标的add操作是把该下标以后的元素都往后移一位,而后把新元素插到空出来的index位
remove操作相当于先获取所有该元素的下标,然后一个个删除
删除操作就是将该下标以后的元素都往前复制移动一位,然后将原来的最后一位设为null等待GC回收
而后将最后一个5设为null等待GC回收
看了源码之后相比再手写一个ArrayList就再轻松不过了!