看了java里ArrayList类的部分源码,做个小结。
变量:
transient Object[] elementData; //存放数据的数组,transient表示这个变量不能被序列化(我也不太懂)
private int size; //当前存放元素的数量
常量(都为private):
int DEFAULT_CAPACITY = 10 //初始化默认容量
Object[] EMPTY_ELEMENTDATA = {}; //如果指定初始容量为0,那elementData就指向这个
Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //如果指定初始容量不为0,那elementData就指向这个。
int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //数组允许最大容量,add方法里有讲解
构造方法:
如果是默认构造ArrayList,size=DEFAULT_CAPACITY,初始化后,加入第一个元素之前,私有成员elementData指向DEFAULTCAPACITY_EMPTY_ELEMENTDATA,大小为0。这样做应该是为了节省空间。
而指定大小的的构造,elementData直接初始化为指定大小的数组。
方法:
1、 给定一个对象,在list中找这个对象,如indexOf,contains方法,实际上是调用了对象的equals方法。给定的对象可以是null。
2、调用add或类似方法时,要检查是否需要扩容。以add(E e)方法为例:
当ArrayList已经有元素时,取size+1作为最小容量,如果最小容量比elementData的length大,那就需要扩容了。扩容,把length和length>>1(length右移一位)相加得到新容量,如果新容量还是比最小容量小,那新容量就等于最小容量。
现在要检查新容量是否超过了允许最大容量(就是MAX_ARRAY_SIZE),如果超过了,就再比较最小容量和允许最大容量,还是超过,那就取Integer.MAX_VALUE;没超过,就取允许最大容量。
最后新建一个新容量数组,把原elementData的元素复制过去,替换elementData。
注意 因为有默认构造这个例外,要先检查elementData是否初始化空,若是则取size+1和默认构造容量的较大值作为最小容量。感觉一般取的都是默认构造容量。
再来看一下MAX_ARRAY_SIZE,源文件里的解释是因为保留了一些数组头部的数据,所以要减8。
还有一个细节,在add时,modCount会自增,modCount是AbstractList里的变量,Arraylist继承AbstractList,那modCount是啥?这涉及到迭代器,简单来说,迭代器开始时会把modCount保留一个副本,在迭代过程中,如果发现modCount和副本不一致,说明set、add、remove等方法在这期间被调用了,数组被修改了,那就会抛出异常ConcurrentModificationException。这就是所说的ArrayList是非线程安全的,通过这样来保证遍历时的正确性。
3、 remove方法 先检查是否越界,移除的如果不是最后一个,就把index后面的元素前移一个单位。然后,最后一个位置指向null,释放内存。
4、对数组的操作,如复制、移动元素,用的方法基本为native,也就是调用了非java代码,如C、C++。
5、遍历器 iterator:
成员:
int cursor; //指向元素下标
int lastRet = -1; //上一个返回的元素,-1表示没有
int expectedModCount = modCount; //用于安全
方法:
public boolean hasNext(): 检查cursor是否越界
public E next():先会检查是否越界,不越界时返回cursor指向的元素,lastRet的值为cursor的值,最后cursor加1
public void remove(): 先会检查lastRet是否小于0,若小于0则说明没有返回元素,会抛出异常。若大于等于0,则调用arrayList的remove方法,以lastRet作为参数;之后 cursor的值赋为lastRet,lastRet变为-1。
说明应该在调用next方法之后,再调用remove方法
ListIterator:
与iterator比较类似,可正序、逆序遍历,可删除、替换元素,可得前一个、后一个下标
SubList:
SubList是一个类,继承自AbstractList,有get、set、add等方法,与arrayList类似。要注意操作subList对象实际上是对父arrayList进行操作,对subList的改变会影响到arrayList