ArrayList原理及源码分析
ArrayList底层源码
底层存储的原始容器
ArrayList用于存储的数组构造器篇
ArrayList的构造器
ArrayList有三个构造器,分别为
无参构造器
这个比较常用,一般写代码的时候创建都会用 new ArrayList<T>()。
带指定数组容量的构造器
这个会在构建的时候传入底层数组的容量。
带其他列表的构造器
这个会在构建的时候直接传入另一个列表。
无参构造器
无参构造器源码内部维护的空数组
直接指向内部维护的空数组。
带指定数组容量的构造器的源码解析
带指定数组容量的构造器源码从源码可以看出实际上此构造器就是为底层的数组引用创建了一个长度为传入长度的数组对象,如果传入长度为0的时候,引用直接指向内部维护的一个空数组,以节约内存。
带其他列表的构造器
带其他列表的构造器源码让内部数组引用指向传入的列表转化的数组,如果长度不为0,验证类型是否为Object[],不是则转化,如果长度为0,让其指向空数组。
方法篇
add()方法
add()方法是往List中添加一个对象
add()源码
首先会调用验证容量是否足够的函数ensureCapacityInternal(int size + 1),然后将size+1并将最后一个指定为添加的元素。
验证容量
当容量不够的时候,便会调用扩容函数
扩容函数
扩容调用了移位,直接将原来的容量除2并加上原来的容量,新数组的容量是原数组的1.5倍,如果还不够,便会指定数组长度为内部维护的数组最大长度。
内部维护的数组最大长度
如果仍然不够,就会与int的最大值对比,如果超出,就会报错。
将得到的新容量,重新创建一个新数组,并将原数组拷贝进去。
add(int index,E element)
add(int index,E element)源码首先检查输入的index是否有问题,然后容量检查,最后对数组进行操作,这是一个插入操作,ArrayList在做插入的时候,性能是不如LinkedList,原因就是出在ArrayList底层是数组存储,需要调用System.arraycopy这个方法,这个方法是一个本地方法,底层是C写的,所以源码看不了,该方法会将index之后的对象全部移位到自己原来的index+1,最后将index这个位置的指定为传入的对象,并把size++。
remove(int index)
remove(int index)首先检查输入的index是否有问题,然后对数组进行操纵,这里跟添加的有一点不一样,需要去把原来末尾的元素清除掉。
remove(Object o)
remove(Object o)首先判空,可以看出,如果想移除容器中的空对象,可以调用这个方法
如果不为空,fastRemove操作对象的方法其实跟remove(int index)操纵对象的方法一样,需要说明的是,如果要调用这个方法,所操作的对象会调用equals去判断是否相同,有条件最好覆写equals方法。