ArrayList源码解读
增加元素
add(E e)
首先检查容量是否满足要求,不满足扩容,满足则在后面的位置上添加元素
1 | public boolean add(E e) { |
add(int index,E e)
首先检查索引,不能小于0,大于size,确保容量满足要求,使用System.arraycopy进行复制,插入数据,最后增加size
1 | public void add(int index, E element) { |
addAll(Collection c)
与add方法类似,首先把c转化为数组,确保容量满足要求,然后用System.arraycopy进行复制,把数据插入到尾部,增加size
1 | public boolean addAll(Collection<? extends E> c) { |
addAll(int index, Collection<? extends E> c)
首先检查索引,确保容量,判断是否有数据需要右移,使用System.arraycopy移动、增加谁,增加size
1 | public boolean addAll(int index, Collection<? extends E> c) { |
扩容
每次扩容1.5倍,如果容量还不够,则使用最小容量,最小容量=现在容量+插入容量
1 | private void grow(int minCapacity) { |
查找对象
indexof()
先判断是是否是null,然后从前往后依次查找,返回第一个目标元素的下标,如果没有匹配目标返回-1
1 | public int indexOf(Object o) { |
lastIndexOf()
先判断是否是null,然后从后向前依次查找,返回第一个目标元素下标,如果没有匹配目标返回-1
1 | public int lastIndexOf(Object o) { |
删除
remove(int index)
删除指定位置的元素,首先检查索引不能小于0大于size,计算是否有需要左移的数据,把删除位置的元素置null,该方法会返回旧值
1 | public E remove(int index) { |
remove(Object o)
删除指定对象,首先检查对象是否是null,然后从前向后查找对象,并调用fastRemove删除
1 |
|
fastRemove与remove类似,但是省掉了范围检查和返回旧值
1 | private void fastRemove(int index) { |
remove(Collection<?> c)
删除集合
1 | public boolean removeAll(Collection<?> c) { |
clear()
清空列表
1 | public void clear() { |
迭代器
ArrayList可以得到两种迭代器,iterator()和listIterator()。iterator()中返回的迭代器只能从前向后遍历,而listIterator()迭代器不仅能反向遍历,还能从指定位置开始遍历。
在操作迭代器时,中途调用了ArrayList的其他改变结构的方法,会抛出异常,即fast-fail机制。在初始化迭代器时,保存当前的modCount,然后在每个操作时,检查当前modCount是否与初始化时的一致,如果不一致,说明进行了改变结构的操作,那么会抛出异常。
iterator()
1 | public Iterator<E> iterator() { |
listIterator()
返回的迭代器可指定迭代下标起始值
1 | public ListIterator<E> listIterator(int index) { |
listIterator迭代器实现,既可以实现前向遍历,也可以实现后项遍历,并且除了删除方法还能够添加、更改数据
1 | private class ListItr extends Itr implements ListIterator<E> { |
需要注意remove()方法的重载
假设有这样的场景:遍历list,删除指定元素
首先想到的方式是下面的方式
1 | List<Integer> list = new ArrayList<Integer>(); |
但是结果却如下:
1 | [-2, 0, 2] |
这段程序并没有按照预期移除偶数元素。出现这种情况的原因是arraylist重载了remove方法,此处程序调用了remove(int index)方法移除了对应下标元素,并没有按照预期调用remove(Object o)方法。remove重载的问题在《effective java》第41条慎用重载中也提及,并指明是由于Java添加范型和自动装箱后破坏了List接口导致。那么如何才能移除偶数元素呢?答案是转换为包装类。
1 | List<Integer> list = new ArrayList<Integer>(); |
对于add方法
我们通常使用Arrays.asList(T t)方法产生List,但是该方法产生的list不能使用add、remove方法
1 | List<Integer> integers = Arrays.asList(1,2,3,4); |
输出
1 | Exception in thread "main" java.lang.UnsupportedOperationException |
这是因为Arrays里实现了一个内部类,也叫做ArrayList,其形式如下
1 | private static class ArrayList<E> extends AbstractList<E> |
该类继承了AbstractList,并实现了其中的部分方法,其中不包括add、remove方法,所以调用两者时实际上调用的是抽象类AbstractList的remove,add方法,而这两个方法在AbstractList的定义如下:
1 | public void add(int index, E element) { |
所以会抛出UnsupportedOpreationExcetion异常,这个特性让Arrays.asList返回的结果是只读的,不能修改。